anchor.diff:      var amount = arguments[1].assertNumber("amount");
       return color.changeHsl(
           saturation: color.saturation - amount.valueInRange(0, 100, "amount"));
  +  }));
  +
  +  environment
  +      .setFunction(new BuiltInCallable("grayscale", r"$color", (arguments) {
  +    if (arguments[0] is SassNumber) {
  +      return new SassString("grayscale(${arguments[0]})");
  +    }
  +
  +    var color = arguments[0].assertColor("color");
  +    return color.changeHsl(saturation: 0);
  +  }));
  +
  +  environment
  +      .setFunction(new BuiltInCallable("complement", r"$color", (arguments) {
  +    var color = arguments[0].assertColor("color");
  +    return color.changeHsl(hue: color.hue + 180);
  +  }));
  +
  +  environment.setFunction(
  +      new BuiltInCallable("invert", r"$color, $weight: 50%", (arguments) {
  +    if (arguments[0] is SassNumber) {
  +      return new SassString("invert(${arguments[0]})");
  +    }
  +
  +    var color = arguments[0].assertColor("color");
  +    var weight = arguments[1].assertNumber("weight");
  +    var inverse = color.changeRgb(
  +        red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue);
  +    if (weight.value == 50) return inverse;
  +
  +    return _mix(color, inverse, weight);
     }));
   
     // ## Introspection
  
positive.code:     var color1 = arguments[0].assertColor("color1");
      var color2 = arguments[1].assertColor("color2");
      var weight = arguments[2].assertNumber("weight");
  
      // This algorithm factors in both the user-provided weight (w) and the
      // difference between the alpha values of the two colors (a) to decide how
      // to perform the weighted average of the two RGB values.
      //
      // It works by first normalizing both parameters to be within [-1, 1], where
      // 1 indicates "only use color1", -1 indicates "only use color2", and all
      // values in between indicated a proportionately weighted average.
      //
      // Once we have the normalized variables w and a, we apply the formula
      // (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color1. This
      // formula has two especially nice properties:
      //
      //   * When either w or a are -1 or 1, the combined weight is also that
      //     number (cases where w * a == -1 are undefined, and handled as a
      //     special case).
      //
      //   * When a is 0, the combined weight is w, and vice versa.
      //
      // Finally, the weight of color1 is renormalized to be within [0, 1] and the
      // weight of color2 is given by 1 minus the weight of color1.
      var weightScale = weight.valueInRange(0, 100, "weight") / 100;
      var normalizedWeight = weightScale * 2 - 1;
      var alphaDistance = color1.alpha - color2.alpha;
  
      var combinedWeight1 = normalizedWeight * alphaDistance == -1
          ? normalizedWeight
          : (normalizedWeight + alphaDistance) /
              (1 + normalizedWeight * alphaDistance);
      var weight1 = (combinedWeight1 + 1) / 2;
      var weight2 = 1 - weight1;
  
      return new SassColor.rgb(
          (color1.red * weight1 + color2.red * weight2).round(),
          (color1.green * weight1 + color2.green * weight2).round(),
          (color1.blue * weight1 + color2.blue * weight2).round(),
          color1.alpha * weightScale + color2.alpha * (1 - weightScale));
    }));
  
    // ## HSL
  
negative.code: 
    return value.clamp(0, max);
  }
  
  SassColor _mix(SassColor color1, SassColor color2, SassNumber weight) {
    // This algorithm factors in both the user-provided weight (w) and the
    // difference between the alpha values of the two colors (a) to decide how
    // to perform the weighted average of the two RGB values.
    //
    // It works by first normalizing both parameters to be within [-1, 1], where
    // 1 indicates "only use color1", -1 indicates "only use color2", and all
    // values in between indicated a proportionately weighted average.
    //
    // Once we have the normalized variables w and a, we apply the formula
    // (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color1. This
    // formula has two especially nice properties:
    //
    //   * When either w or a are -1 or 1, the combined weight is also that
    //     number (cases where w * a == -1 are undefined, and handled as a
    //     special case).
    //
    //   * When a is 0, the combined weight is w, and vice versa.
    //
    // Finally, the weight of color1 is renormalized to be within [0, 1] and the
    // weight of color2 is given by 1 minus the weight of color1.
    var weightScale = weight.valueInRange(0, 100, "weight") / 100;
    var normalizedWeight = weightScale * 2 - 1;
    var alphaDistance = color1.alpha - color2.alpha;
  
    var combinedWeight1 = normalizedWeight * alphaDistance == -1
        ? normalizedWeight
        : (normalizedWeight + alphaDistance) /
            (1 + normalizedWeight * alphaDistance);
    var weight1 = (combinedWeight1 + 1) / 2;
    var weight2 = 1 - weight1;
  
    return new SassColor.rgb(
        (color1.red * weight1 + color2.red * weight2).round(),
        (color1.green * weight1 + color2.green * weight2).round(),
        (color1.blue * weight1 + color2.blue * weight2).round(),
        color1.alpha * weightScale + color2.alpha * (1 - weightScale));
  }
  