/* ============================================================================
   FormBuilder.Blazor — jf- layer
   Link as: <link href="_content/FormBuilder.Blazor/jsonforms.css" rel="stylesheet" />

   Two rules about what lives here.

   1. Design tokens. Everything below is expressed in terms of the custom properties on :root, so
      a host retheming the forms overrides tokens rather than out-specifying selectors. Redefine
      any of them on :root, on a wrapper element, or on .jf-form itself — the cascade carries them
      down and nothing here uses !important.

   2. Only what cannot be scoped. Per-component structural layout belongs in that component's
      .razor.css, where CSS isolation keeps it from leaking. What stays global is the vocabulary
      shared across components: .jf-field is rendered by both ControlShell and UnsupportedControl,
      and ControlShell has no .razor.css at all, so its elements carry no scope attribute for an
      isolated rule to hook. The flash keyframes are global for the same reason — they are applied
      by ControlShell, and animation names are document-wide regardless.
   ============================================================================ */

:root {
    /* --- colour ---------------------------------------------------------- */
    --jf-color-text: #212529;
    --jf-color-muted: #6c757d;
    --jf-color-border: #ced4da;
    --jf-color-surface: #fff;
    --jf-color-error: #d32f2f;
    --jf-color-on-error: #fff;

    /* A wash light enough to sit behind text. Used by the invalid state and by the submit flash,
       so they read as the same signal at two intensities. */
    --jf-color-error-wash: rgba(211, 47, 47, 0.09);

    --jf-color-accent: #1274ac;
    --jf-color-accent-wash: rgba(18, 116, 172, 0.1);

    /* Neutral, not a tint of the accent. The selectable-card controls use this for hover and the
       accent wash for the selected state, so the two read as different things. */
    --jf-color-hover: #f9fafb;

    /* --- spacing --------------------------------------------------------- */
    --jf-gap: 1rem;         /* between sibling form elements */
    --jf-gap-sm: 0.5rem;
    --jf-gap-xs: 0.25rem;   /* label to input */
    --jf-pad: 0.75rem;

    /* --- type ------------------------------------------------------------ */
    --jf-label-size: 0.9375rem;
    --jf-label-weight: 500;
    --jf-hint-size: 0.875rem;
    --jf-title-size: 1.25rem;
    --jf-title-weight: 500;

    /* --- shape ----------------------------------------------------------- */
    --jf-radius: 0.5rem;
    --jf-radius-sm: 0.25rem;

    /* --- layout ---------------------------------------------------------- */
    /* Narrowest a HorizontalLayout column may get before it wraps to its own row. Raising this
       makes horizontal layouts stack sooner on narrow viewports. */
    --jf-column-min: 13rem;

    /* --- motion ---------------------------------------------------------- */
    --jf-flash-duration: 1.1s;
}

/* ============================================================================
   Form shell
   ============================================================================ */

.jf-form {
    display: flex;
    flex-direction: column;
    gap: var(--jf-gap);
    color: var(--jf-color-text);
}

.jf-form-error {
    padding: var(--jf-pad);
    border: 1px solid var(--jf-color-error);
    border-radius: var(--jf-radius);
    background: var(--jf-color-error-wash);
    color: var(--jf-color-error);
}

/* ============================================================================
   Field chrome — ControlShell and UnsupportedControl
   ============================================================================ */

.jf-field {
    display: flex;
    flex-direction: column;
    gap: var(--jf-gap-xs);

    /* The flash animates this, so it needs a resting value to animate away from. Declaring it
       here rather than only in the keyframes also stops the field from jumping when the
       animation ends and the computed style snaps back. */
    background: transparent;
    border-radius: var(--jf-radius-sm);
}

/* The margin reset is load-bearing, not tidiness. Bootstrap 4 — which the Site and most hosts
   load — sets `label { display: inline-block; margin-bottom: .5rem }`. The previous implementation
   rendered its caption as a <div><span> and so never picked that up; ControlShell uses a real
   <label>, which inherits the margin and stacks it on top of .jf-field's own gap, doubling the
   space under every caption in the form.

   Reset here rather than by shrinking --jf-gap-xs: the token is the honest control over that
   spacing, and compensating in it would make the gap come out wrong again on a host that does not
   load Bootstrap. */
.jf-field__label {
    display: block;
    margin: 0;

    font-size: var(--jf-label-size);
    font-weight: var(--jf-label-weight);
    line-height: 1.3;
}

.jf-field__required {
    margin-left: 0.15em;
    color: var(--jf-color-error);
}

/* A slot, nothing more. Do not add width rules for what goes inside it: the Kendo theme already
   declares `.k-input, .k-picker { width: 100%; min-width: 0 }`, so an input fills whatever
   containing block the layout gives it. Sizing belongs to the layouts — .jf-vertical stretches its
   children, .jf-horizontal sets the track width — and reaching down from here to restyle a
   vendor component only fights a theme that is already doing the right thing. */
.jf-field__input {
    min-width: 0;
}

.jf-field__hint {
    font-size: var(--jf-hint-size);
    color: var(--jf-color-muted);
}

/* Replaces text-danger. */
.jf-field__error {
    font-size: var(--jf-hint-size);
    color: var(--jf-color-error);
}

.jf-field--invalid > .jf-field__label {
    color: var(--jf-color-error);
}

/* ============================================================================
   Static and fallback elements
   ============================================================================ */

.jf-label {
    font-size: var(--jf-title-size);
    font-weight: var(--jf-title-weight);
    line-height: 1.2;
}

.jf-html > *:first-child { margin-top: 0; }
.jf-html > *:last-child { margin-bottom: 0; }

/* Deliberately conspicuous: an unrendered control is a schema problem someone needs to see. */
.jf-unsupported {
    padding: var(--jf-pad);
    border: 1px dashed var(--jf-color-error);
    border-radius: var(--jf-radius);
    background: var(--jf-color-error-wash);
}

.jf-unsupported small {
    font-size: var(--jf-hint-size);
    color: var(--jf-color-muted);
}

/* BooleanControl's card lives in BooleanControl.razor.css — it has a single owner, so it belongs
   in that component's scoped sheet rather than up here. */

/* ============================================================================
   Submit flash

   FormElementBase.FlashClass alternates between these two on the parity of the store's highlight
   token. They are identical on purpose: a CSS animation only restarts when the element gains an
   animation-name it did not already have, and toggling one class off and on within a single
   Blazor render is not a frame gap the browser can observe. Swapping between two names restarts
   it every time, so a second submit flashes as visibly as the first.

   Keep both blocks in step if you change one.
   ============================================================================ */

@keyframes jf-flash-a {
    0%, 100% { background: transparent; box-shadow: 0 0 0 0 transparent; }
    15%, 45% { background: var(--jf-color-error-wash); box-shadow: 0 0 0 3px var(--jf-color-error-wash); }
    30%, 60% { background: transparent; box-shadow: 0 0 0 0 transparent; }
}

@keyframes jf-flash-b {
    0%, 100% { background: transparent; box-shadow: 0 0 0 0 transparent; }
    15%, 45% { background: var(--jf-color-error-wash); box-shadow: 0 0 0 3px var(--jf-color-error-wash); }
    30%, 60% { background: transparent; box-shadow: 0 0 0 0 transparent; }
}

.jf-flash-a { animation: jf-flash-a var(--jf-flash-duration) ease-in-out; }
.jf-flash-b { animation: jf-flash-b var(--jf-flash-duration) ease-in-out; }

@media (prefers-reduced-motion: reduce) {
    /* Drop the motion, keep the signal. The flash is the only thing telling a user that a submit
       failed on a field scrolled out of view, so removing the animation without leaving a static
       marker in its place would take the information away rather than just the movement. */
    .jf-flash-a,
    .jf-flash-b {
        animation: none;
        background: var(--jf-color-error-wash);
        box-shadow: 0 0 0 3px var(--jf-color-error-wash);
    }
}
