                        Changes in version 0.3.0                        

Corrections (results from 0.2.0 may change)

  - nl_predict(): standard errors and intervals for lmer/glmer models
    were computed from a spline basis rebuilt on the prediction grid
    instead of the basis used in estimation. They are now computed with
    the estimation basis. Point predictions were not affected.
  - nl_derivatives(): interval estimates treated neighbouring
    predictions as independent, which made slope and curvature intervals
    far too wide (by a factor of 10 to 100 in tests). Derivatives are
    now computed from the model with the full covariance matrix. The
    function now takes the fitted model: nl_derivatives(fit). Passing a
    prediction table still returns point estimates, with a warning and
    no intervals.
  - Automatic df selection (df = "auto"), nl_knots(), and nl_compare()
    used REML likelihoods for Gaussian mixed models, which are not
    comparable across different fixed effects. All comparisons now use
    maximum likelihood. The final model is still fitted by REML unless
    REML = FALSE.
  - nl_r2() and nl_icc() ignored random-slope variances. They now
    include them, averaged over the data (Johnson 2014); nl_icc() warns
    that the ICC then depends on x.
  - nl_fit(cluster = c("student", "school"), nested = TRUE) built (1 |
    student/school), i.e. schools nested in students, contrary to the
    documentation, and so omitted the school-level variance. It now
    builds (1 | school/student): the first variable is nested within the
    second.
  - nl_r2(): complementary log-log models now use pi^2/6 as the
    distribution-specific variance.
  - nl_het(): cluster-specific curves for non-Gaussian models were on
    the link scale while the population curve was on the response scale;
    both are now on the response scale. The output slope_variance (which
    was the SD of predicted values, not of slopes) is renamed
    between_cluster_sd.

New features

  - nl_fit(random = ) accepts any lme4 random-effects specification,
    e.g. "(1 | school/student)" or "(1 | idcode) + (1 | indcode)".
  - nl_predict(type = "marginal") gives population-averaged curves for
    GLMMs; scale = "link" gives the linear predictor. The documentation
    now states exactly what is predicted.
  - controls accepts expressions such as "factor(race)" or "I(age^2)".
  - nl_wald(): joint Wald test that all coefficients involving x are
    zero.
  - nl_fit() warns when x has too few distinct values for the requested
    df.
  - The data used in estimation are stored in the fit, so nl_compare()
    and nl_het() no longer need to find the original data frame.
  - nl_plot(type = "combo") returns one combined figure (via patchwork
    when installed) instead of a list, so it can be saved with ggsave().
  - nl_plot() and nl_turning_points() read the variable names from their
    input, so x no longer has to be repeated.

                 Changes in version 0.2.0 (2026-04-16)                  

Major new features

  - Two-way and nested clustering via cluster = c("g1","g2") and nested
    = TRUE/FALSE, generating (1|g1/g2) or (1|g1) + (1|g2) random-effects
    structures in lme4.

  - Automatic knot / df selection (df = "auto" in nl_fit() or via
    nl_knots()) using AIC or BIC over a user-specified grid.

  - Multilevel R-squared decomposition (nl_r2()): Nakagawa-Schielzeth
    marginal R2m and conditional R2c, plus a level-specific variance
    partition table (r2_mlm style) for LMM, GLMM, and single-level OLS /
    GAM models.

  - Full postestimation suite:
    
      - nl_derivatives() — first and second derivatives with
        delta-method confidence bands.
      - nl_turning_points() — local maxima, minima, inflection regions,
        and slope-direction regions.
      - nl_plot() gains type = "slope", "curvature", and "combo" in
        addition to the original "trajectory".

  - Built-in model comparison workflow (nl_compare()): contrasts linear,
    polynomial, and spline fits by AIC, BIC, log-likelihood, and
    likelihood-ratio tests.

  - B-spline basis (method = "bs", bs_degree argument).

  - Random spline slopes (random_slope = TRUE) to allow the nonlinear
    effect to vary across clusters.

  - Cluster heterogeneity analysis (nl_het()): plots cluster-specific
    trajectories (BLUPs) and performs an LRT comparing random-slope vs
    random-intercept models.

  - CI for glmerMod: approximate confidence intervals via the delta
    method on the link scale (default, fast) or parametric bootstrap
    (glmer_ci = "boot").

Breaking changes

None. All v0.1.0 calls remain valid.

Bug fixes

  - nl_r2() variance partition now correctly excludes NA entries that
    could appear when lme4 internal row names are ambiguous in nested
    models.
  - nl_predict() now correctly computes CI when control variables are
    stored as character (not factor) in the original data.
  - nl_plot() no longer errors when time = NULL and the data frame has
    no time column.

Dependency changes

  - %||% is now imported from rlang rather than defined internally,
    avoiding namespace masking.
  - reformulas moved from Imports to Suggests (used opportunistically
    for nobars(); falls back to lme4::nobars() if unavailable).

                        Changes in version 0.1.0                        

  - Initial release: nl_fit(), nl_predict(), nl_plot(), nl_summary(),
    nl_icc().
