/*! PolyFishCSS-Forms.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Everything a real form needs beyond the four controls in Content: sizes,
 * floating labels, validation feedback, fieldsets, range and file inputs,
 * inline checks, form layout rows and character counters.
 *
 * Depends on: PolyFishCSS-Core.css and PolyFishCSS-Content.css
 *             (.pf-input, .pf-label, .pf-help, .pf-field, .pf-select).
 * Load order: after Content, before Utilities.
 *
 * CONTENTS
 *   1. Sizes
 *   2. Floating labels
 *   3. Validation states and feedback
 *   4. Fieldsets and legends
 *   5. Range
 *   6. File input
 *   7. Checks and radios
 *   8. Form layout
 *   9. Counters and hints
 *
 * THE RULE THAT MATTERS MORE THAN ANY STYLE
 *   Every control needs a programmatic name. A <label for>, or aria-label, or
 *   aria-labelledby. A placeholder is not a name: it vanishes on focus, fails
 *   contrast in most palettes and is skipped by some screen readers. The
 *   floating-label pattern below exists precisely so a form can look like it
 *   uses placeholders while actually using labels.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.forms`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.forms {
  /* ==========================================================================
     #SIZES
     ========================================================================== */
  
  /**
   * <input class="pf-input pf-input--sm">
   *
   * Padding is in em so a size modifier only changes font-size. Note there is
   * no size below --sm: at 12px a text field stops being comfortably tappable,
   * and Core's pointer:coarse floor would fight it anyway.
   */
  .pf-input--sm,
  .pf-select--sm { font-size: var(--pf-text-xs); padding: 0.55em 0.7em; }
  .pf-input--lg,
  .pf-select--lg { font-size: var(--pf-text-base); padding: 0.85em 1em; }
  
  /* ==========================================================================
     #FLOATING LABELS
     ========================================================================== */
  
  /**
   * Floating label
   *
   * <div class="pf-float">
   *   <input class="pf-input" id="email" type="email" placeholder=" ">
   *   <label class="pf-float__label" for="email">Email address</label>
   * </div>
   *
   * The input comes FIRST and the label second, so :placeholder-shown and
   * :focus can select the label as a sibling. The placeholder must be a single
   * space - an empty placeholder attribute counts as shown in some engines and
   * the label never lifts.
   *
   * This is a real <label for>, so the control keeps its accessible name at
   * every state. That is the entire reason to prefer it over a placeholder.
   */
  .pf-float { position: relative; }
  .pf-float .pf-input,
  .pf-float .pf-select,
  .pf-float .pf-textarea { padding-top: 1.4em; padding-bottom: 0.5em; }
  .pf-float__label {
    position: absolute;
    top: 0.85em;
    inset-inline-start: 0.95em;
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    pointer-events: none;
    transform-origin: 0 0;
    transition: transform var(--pf-speed) var(--pf-ease), color var(--pf-speed) var(--pf-ease);
  }
  .pf-float .pf-input:focus + .pf-float__label,
  .pf-float .pf-input:not(:placeholder-shown) + .pf-float__label,
  .pf-float .pf-textarea:focus + .pf-float__label,
  .pf-float .pf-textarea:not(:placeholder-shown) + .pf-float__label,
  .pf-float .pf-select + .pf-float__label {
    transform: translateY(-0.7em) scale(0.78);
  }
  .pf-float .pf-input:focus + .pf-float__label,
  .pf-float .pf-textarea:focus + .pf-float__label { color: var(--pf-accent); }
  
  /* ==========================================================================
     #VALIDATION STATES AND FEEDBACK
     ========================================================================== */
  
  /**
   * Validation
   *
   * <div class="pf-field">
   *   <label class="pf-label" for="pw">Password</label>
   *   <input class="pf-input" id="pw" type="password"
   *          aria-invalid="true" aria-describedby="pw-err">
   *   <p class="pf-feedback pf-feedback--error" id="pw-err">
   *     At least twelve characters.
   *   </p>
   * </div>
   *
   * State hangs off aria-invalid, not a class, so the styling and the
   * announcement can never disagree. The message is joined to the field with
   * aria-describedby - without that a screen reader says "invalid" and never
   * says why.
   *
   * :user-invalid is used rather than :invalid deliberately. :invalid matches
   * an empty required field the moment the page loads, which paints a form red
   * before anyone has typed. :user-invalid waits until the field has been
   * interacted with.
   */
  .pf-feedback {
    display: flex;
    align-items: flex-start;
    gap: 0.45em;
    font-size: var(--pf-text-xs);
    line-height: 1.45;
  }
  .pf-feedback::before {
    content: "";
    width: 0.7em;
    height: 0.7em;
    margin-top: 0.35em;
    flex: none;
    background: currentColor;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-feedback--error { color: #e08f8f; }
  .pf-feedback--ok { color: var(--pf-accent); }
  .pf-feedback--ok::before { clip-path: circle(50%); }
  .pf-feedback--hint { color: var(--pf-text-muted); }
  .pf-feedback--hint::before { display: none; }
  
  .pf-input[aria-invalid="true"],
  .pf-select[aria-invalid="true"],
  .pf-textarea[aria-invalid="true"],
  .pf-input:user-invalid,
  .pf-textarea:user-invalid { border-color: #e08f8f; }
  
  .pf-input[aria-invalid="true"]:focus,
  .pf-input:user-invalid:focus { box-shadow: 0 0 0 3px rgba(224, 143, 143, 0.3); }
  
  .pf-input[data-pf-valid]:not([aria-invalid="true"]) { border-color: var(--pf-accent); }
  
  /* A required marker that is decorative to assistive tech - the `required`
     attribute already announces it, and "asterisk" read aloud is noise. */
  .pf-label--required::after {
    content: "*";
    color: var(--pf-accent-2);
    margin-inline-start: 0.25em;
  }
  
  /* ==========================================================================
     #FIELDSETS AND LEGENDS
     ========================================================================== */
  
  /**
   * <fieldset class="pf-fieldset">
   *   <legend class="pf-legend">Notifications</legend>
   *   ...
   * </fieldset>
   *
   * A group of radios or checkboxes needs a fieldset and legend, not a heading.
   * The legend is what associates the question with every option in the group.
   */
  .pf-fieldset {
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-5);
    min-width: 0;
  }
  .pf-fieldset--plain { border: 0; padding: 0; }
  .pf-legend {
    color: var(--pf-text);
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-sm);
    font-weight: 600;
    padding-inline: var(--pf-space-2);
  }
  .pf-fieldset--plain > .pf-legend { padding-inline: 0; }
  
  /* ==========================================================================
     #RANGE
     ========================================================================== */
  
  /**
   * <input class="pf-range" type="range" min="10" max="600" step="10">
   *
   * Track and thumb have to be declared per engine - there is still no
   * interoperable shorthand - so the rules are duplicated rather than combined.
   * A combined selector list would be dropped whole by any engine that does not
   * recognise one of the pseudo-elements.
   */
  .pf-range {
    width: 100%;
    height: 1.5rem;
    appearance: none;
    background: none;
    cursor: pointer;
  }
  .pf-range:focus-visible { outline: 2px solid var(--pf-focus); outline-offset: 4px; }
  
  .pf-range::-webkit-slider-runnable-track {
    height: 0.35rem;
    background: var(--pf-surface-raised);
    border-radius: var(--pf-radius-pill);
  }
  .pf-range::-moz-range-track {
    height: 0.35rem;
    background: var(--pf-surface-raised);
    border-radius: var(--pf-radius-pill);
  }
  .pf-range::-webkit-slider-thumb {
    appearance: none;
    width: 1.1rem;
    height: 1.1rem;
    margin-top: -0.375rem;
    background: var(--pf-accent);
    border: 0;
    border-radius: 50%;
  }
  .pf-range::-moz-range-thumb {
    width: 1.1rem;
    height: 1.1rem;
    background: var(--pf-accent);
    border: 0;
    border-radius: 50%;
  }
  
  /* ==========================================================================
     #FILE INPUT
     ========================================================================== */
  
  /**
   * <input class="pf-file" type="file">
   *
   * The button part is styled through ::file-selector-button rather than the
   * old trick of hiding the input behind a label. The native control keeps its
   * keyboard behaviour and its "no file chosen" text, which a fake one loses.
   */
  .pf-file {
    width: 100%;
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    padding: 0.5rem;
  }
  .pf-file::file-selector-button {
    margin-inline-end: 0.75rem;
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text);
    cursor: pointer;
    font: inherit;
    padding: 0.4rem 0.8rem;
  }
  .pf-file::file-selector-button:hover { border-color: var(--pf-border-strong); }
  .pf-file:focus-visible { outline: 2px solid var(--pf-focus); outline-offset: 2px; }
  
  /* ==========================================================================
     #CHECKS AND RADIOS
     ========================================================================== */
  
  /**
   * <div class="pf-checks-group">
   *   <label class="pf-choice"><input type="checkbox"> Daily</label>
   *   <label class="pf-choice"><input type="checkbox"> Weekly</label>
   * </div>
   *
   * Stack by default, inline on request. The card variant turns each option
   * into a selectable tile, which is the pattern for plan pickers.
   */
  .pf-checks-group { display: grid; gap: var(--pf-space-3); }
  .pf-checks-group--inline { display: flex; flex-wrap: wrap; gap: var(--pf-space-5); }
  
  .pf-choice-card {
    display: flex;
    align-items: flex-start;
    gap: var(--pf-space-3);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    cursor: pointer;
    padding: var(--pf-space-4);
    transition: border-color var(--pf-speed) var(--pf-ease), background-color var(--pf-speed) var(--pf-ease);
  }
  .pf-choice-card:hover { border-color: var(--pf-border-strong); }
  .pf-choice-card input { accent-color: var(--pf-accent); margin-top: 0.2rem; }
  .pf-choice-card:has(input:checked) {
    border-color: var(--pf-accent);
    background: var(--pf-accent-wash, rgba(143, 224, 106, 0.12));
  }
  .pf-choice-card:has(input:focus-visible) { outline: 2px solid var(--pf-focus); outline-offset: 2px; }
  .pf-choice-card__title { font-weight: 600; font-size: var(--pf-text-sm); }
  .pf-choice-card__body { color: var(--pf-text-muted); font-size: var(--pf-text-xs); }
  
  /* ==========================================================================
     #FORM LAYOUT
     ========================================================================== */
  
  /**
   * <form class="pf-form">
   *   <div class="pf-form__row pf-form__row--2"> ... two fields ... </div>
   *   <div class="pf-field"> ... </div>
   *   <div class="pf-form__actions"> ... buttons ... </div>
   * </form>
   *
   * Rows collapse to one column below 620px. The actions row aligns right on a
   * wide screen and goes full width on a narrow one, because a half-width
   * primary button on a phone is a smaller target for no reason.
   */
  .pf-form { display: grid; gap: var(--pf-space-5); }
  .pf-form__row { display: grid; gap: var(--pf-space-4); }
  .pf-form__row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pf-form__row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .pf-form__row--split { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .pf-form__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--pf-space-3);
  }
  
  @media (max-width: 620px) {
    .pf-form__row--2,
    .pf-form__row--3,
    .pf-form__row--split { grid-template-columns: minmax(0, 1fr); }
    .pf-form__actions > .pf-btn { flex: 1; }
  }
  
  /* Horizontal form: label beside the control, for settings screens. */
  .pf-field--horizontal {
    display: grid;
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
    align-items: start;
    gap: var(--pf-space-4);
  }
  .pf-field--horizontal .pf-help { grid-column: 2; }
  @media (max-width: 760px) {
    .pf-field--horizontal { grid-template-columns: minmax(0, 1fr); }
    .pf-field--horizontal .pf-help { grid-column: 1; }
  }
  
  /* ==========================================================================
     #COUNTERS AND HINTS
     ========================================================================== */
  
  /**
   * <div class="pf-field">
   *   <div class="pf-label-row">
   *     <label class="pf-label" for="bio">Bio</label>
   *     <span class="pf-counter">0 / 280</span>
   *   </div>
   *   <textarea class="pf-textarea" id="bio" maxlength="280"></textarea>
   * </div>
   *
   * The count itself needs a script - CSS cannot read a value's length. What is
   * here is the layout and the styling, so the script only has to set text.
   * Mark the counter aria-live="polite" if you update it on every keystroke.
   */
  .pf-label-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--pf-space-3);
  }
  .pf-counter {
    color: var(--pf-text-muted);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-xs);
    font-variant-numeric: tabular-nums;
  }
  .pf-counter--over { color: #e08f8f; }
}
