> becomes
+[=invalid at computed-value time=].
+
+Evaluating Custom Functions {#evaluating-custom-functions}
+----------------------------------------------------------
+
+
+ To evaluate a custom function,
+ with |function| being a [=custom function=],
+ |dashed function| being the <> invoking that |function|,
+ and |dependency values| being a [=list=] of values.
+
+ 1. If the number of values in |dashed function|'s argument list
+ is greater than the number of values in |function|'s [=function parameter|parameters=],
+ return failure.
+ 2. For each value |parameter| in |function|'s [=function parameter|parameters=],
+ let |argument| be the corresponding value in |dashed function|'s argument list
+ at the same index:
+ * If |argument| does not exist,
+ set |argument| to the [=guaranteed-invalid value=].
+ * Replace the value in |dashed function|'s argument list
+ with the result of [=resolving an argument=],
+ using |argument| as value,
+ and |parameter| as parameter.
+ 3. Let |result| be the [=resolved local value=]
+ of the '@function/result' descriptor,
+ using |function|, |dashed function|, and |dependency values|.
+ 4. If |function| has a [=return type=],
+ set |result| to the result of [=resolve a typed value|resolving a typed value=],
+ using |result| as the value,
+ and the [=syntax definition=] associated with the [=return type=] as the syntax.
+ 5. If |result| is the [=guaranteed-invalid value=],
+ return failure.
+ 6. Otherwise,
+ return |result|.
+
+
+
+ To
resolve an argument,
+ with value |value|,
+ and [=function parameter|parameter=] |parameter|:
+
+ 1. If |value| is not the [=guaranteed-invalid value=],
+ and |parameter| has a [=parameter type|type=],
+ set |value| to the result of [=resolve a typed value|resolving a typed value=]
+ using |value| as the value,
+ and the [=syntax definition=] associated with |parameter|'s type as the syntax.
+
This step may cause |value| to become [=guaranteed-invalid value|guaranteed-invalid=].
+ 2. If |value| is the [=guaranteed-invalid value=],
+ and |parameter| has a [=default value=],
+ set |value| to one of the following:
+
+ : If |parameter| has a [=parameter type|type=]
+ :: The result of [=resolve a typed value|resolving a typed value=]
+ using the |parameter|'s [=default value=] as the value,
+ and the [=syntax definition=] associated with |parameter|'s type as the syntax.
+
+ : Otherwise
+ :: The |parameter|'s [=default value=].
+
+ 3. Return |value|.
+
+
+
+
+ To
resolve a typed value,
+ with value |value|,
+ and [=syntax definition=] |syntax|:
+
+ 1. If |value| is the [=guaranteed-invalid value=],
+ return |value|.
+ 2.
Compute
+ |value| as if it were the value associated with a [=registered custom property=]
+ whose [=syntax definition=] is |syntax|.
+ 3. If this would lead to a declaration being [=invalid at computed-value time=],
+ return the [=guaranteed-invalid value=].
+ 4. Otherwise, return that value.
+
+
+Parameters and Locals {#parameters}
+-----------------------------------
+
+ The [=function parameters=] and [=function dependencies=] of a [=custom function=]
+ are available for [=locally substitute a var()|local substitution=]
+ as if they were declared as [=local variables=]
+ at the start of the ''@function'' rule body.
+
+ Note: A [=local variable=] with the same name
+ as a [=function parameter=]/[=function dependency=] is allowed,
+ but will make the parameter/dependency unreachable
+ for [=locally substitute a var()|substitution=]
+
+ A local variable
+ is a custom property defined with the body of a [=custom function=].
+ It is only visible within the function where it is defined.
+
+
+ To
locally substitute a var() within a value,
+ with |function| being a [=custom function=],
+ |dashed function| being the <
> invoking that |function|,
+ and |dependency values| being a [=list=] of values:
+
+ 1. Let |substitution value| be one of the following options,
+ depending on the [=custom property=] named in the first argument of the ''var()'' function:
+
+
+ : If the [=custom property=] name matches a [=local variable=] within |function|
+ :: The [=resolved local value=] of that [=local variable=].
+
+ : Otherwise, if the [=custom property=] name matches a [=function parameter|parameter=] within |function|
+ :: The corresponding argument value within the |dashed function|.
+
+ : Otherwise, if the [=custom property=] name matches a [=function dependency|dependency=] within |function|
+ :: The corresponding value of that [=function dependency|dependency=]
+ within |dependency values|.
+
+ : Otherwise
+ :: The [=guaranteed-invalid value=].
+
+
+ 2. If |substitution value| is not the [=guaranteed-invalid value=],
+ replace the ''var()'' function by that value.
+
+ 3. Otherwise, if the ''var()'' function has a fallback value as its second argument,
+ replace the ''var()'' function by the [=resolved local value|locally resolved=] fallback value.
+
+ 4. Otherwise, return failure.
+
+
+A resolved local value is the value of a [=local variable=] or [=descriptor=], except:
+
+* Any ''var()'' functions are replaced by [=locally substitute a var()|local substitution=].
+* Any ''env()'' or ''attr()'' functions are substituted normally.
+* Any <>s are replaced by [=substitute a dashed function|dashed function substitution=].
+
+If any substitution algorithm returns failure,
+then the [=resolved local value=] of a [=local variable=]
+is the [=guaranteed-invalid value=].
+
+Cycles {#cycles}
+----------------
+
+Issue: TODO
+
+
+
+Execution Model of Custom Functions {#execution-model}
+======================================================
+
+Like the rest of CSS,
+[=custom functions=] adhere to a declarative model.
+
+The [=local variable=] descriptors
+and '@function/result' descriptor
+can appear in any order,
+and may be provided multiple times.
+If this happens, then declarations appearing later win over earlier ones.
+
+
+
+ @function --mypi() {
+ result: 3;
+ result: 3.14;
+ }
+
+ The value of the '@function/result' descriptor of
--mypi
+ is
3.14
.
+
+
+
+
+
+ @function --circle-area(--r) {
+ result: calc(pi * var(--r2));
+ --r2: var(--r) * var(--r);
+ }
+
+ [=Local variable=] descriptors may appear before or after
+ they are referenced.
+
+
+
+Conditional Rules {#conditional-rules}
+--------------------------------------
+
+A [=conditional group rule=] that appears within a ''@function''
+becomes a [=nested group rule=],
+with the additional restriction
+that only descriptors allowed within ''@function''
+are allowed within the [=nested group rule=].
+
+[=Conditional group rules=] within ''@function''
+are processed as normal,
+acting as if the contents of the rule were present
+at the [=conditional group rule=]'s location
+when the condition is true,
+or acting as if nothing exists at that location otherwise.
+
+
+
+ @function --suitable-font-size() {
+ result: 16px;
+ @media (width > 1000px) {
+ result: 20px;
+ }
+ }
+
+ The value of the '@function/result' descriptor
+ is
20px
if the media query's condition is true,
+ and
16px
otherwise.
+
+
+
+
+ Note that due to the execution model,
+ "early return" is not possible within a ''@function'':
+
+ @function --suitable-font-size() {
+ @media (width > 1000px) {
+ result: 20px;
+ }
+ result: 16px;
+ }
+
+ The value of the '@function/result' descriptor
+ is always
16px
in the above example.
+
+
+
+
+ [=Local variables=] are also valid within conditional rules:
+
+ @function --suitable-font-size() {
+ --size: 16px;
+ @media (width > 1000px) {
+ --size: 20px;
+ }
+ result: var(--size);
+ }
+
+
+
+
+Interaction with @nest {#at-nest}
+----------------------------
+
+''@nest'' rules are valid within ''@function'',
+with the additional restriction
+that only descriptors allowed within ''@function''
+are allowed within the ''@nest'' rule.
+
+A ''@nest'' rule within ''@function'' does nothing:
+it acts like its contents were present at its location.
+
+
+
+CSSOM {#cssom}
+==============
+
+The {{CSSFunctionRule}} interface represents a ''@function'' rule.
+
+
+[Exposed=Window]
+interface CSSFunctionRule : CSSGroupingRule { };
+
+
+While declarations may be specified directly within a ''@function'' rule,
+they are not represented as such in the CSSOM.
+Instead, consecutive segments of declarations
+appear as if wrapped in ''@nest'' rules.
+
+Note: This also applies to the "leading" declarations in the ''@function'' rule,
+ i.e those that do not follow another nested rule.
+
+
+
+ @function --bar() {
+ --x: 42;
+ result: var(--y);
+ @media (width > 1000px) {
+ /* ... */
+ }
+ --y: var(--x);
+ }
+
+
+ The above will appear in the CSSOM as:
+
+
+ @function --bar() {
+ @nest {
+ --x: 42;
+ result: var(--y);
+ }
+ @media (width > 1000px) {
+ /* ... */
+ }
+ @nest {
+ --y: var(--x);
+ }
+ }
+
+
+
+Issue: Should we indeed use ''@nest'' for this purpose?
+ The style
attribute of the ''@nest'' rule
+ should probably not be a regular {{CSSStyleDeclaration}},
+ since only custom properties
+ and the '@function/result' descriptor
+ are relevant.