Css Scoped Custom Property Ignored When Used to Calculate Variable in Outer Scope

Can I use a custom property with fallback to define part of a custom property

CSS variables don't work in the way that you are trying to use them. Variables that are defined with other variables only take variables on the same level or levels above them.

A nice "hack" that I found was, instead of using the :root selector, use the universal selector * to define the varibales on all levels. That way, since you define the color variables on the same level, changing the opacity variable works. Keep in mind that this might cause some unwanted results, and if you want to consider other solutions, these might help you:

CSS scoped custom property ignored when used to calculate variable in outer scope

Overriding :root CSS variables from inner scopes

* {
--opacity: 50;
--clr-900: hsla(36, 83%, 0%, var(--opacity, 1));
--clr-700: hsla(36, 83%, 30%, var(--opacity, 1));
--clr-300: hsla(36, 83%, 70%, var(--opacity, 1));
--clr-200: hsla(36, 83%, 85%, var(--opacity, 1));
--clr-100: hsla(36, 83%, 100%, var(--opacity, 1));
}

.test1 {
background-color: var(--clr-900);
}

.test2 {
--opacity: 0.65;
background-color: var(--clr-900);
}
<p class="test1">hello world</p>
<p class="test2">hello world</p>

Explain this CSS custom properties behavior

--hover-color resolves to the --color value of the scope in which it exists, meaning it will compute the value detected at that time. This is to avoid dependency cycles. You can read about these cycles in the specification document.

Custom properties are left almost entirely unevaluated, except that they allow and evaluate the var() function in their value. This can create cyclic dependencies where a custom property uses a var() referring to itself, or two or more custom properties each attempt to refer to each other.

To prevent this, you would want to expand a bit, and do the following:

:root {
--color: red;
--hover-color: var(--color);
}

div {
--color: green;
--hover-color: var(--color); /* Added this here */

background: var(--color);
}

div:hover {
background: var(--hover-color);
}
<div>
I am green on hover, as expected.
</div>

CSS custom property change on inherited (color) value doesn't work

The property is properly redefined, but until you don't set the color property then the element .bar inherits the color from its parent, and in the scope of the parent that color is red.

:root {  --color: red;  --color2: blue;}
.foo { color: var(--color);}
.bar { --color: var(--color2); color: var(--color);}
<div class="foo">  foo  <div class="bar">    bar  </div></div>

Why does the Cascade for CSS Custom Properties Not Work?

In your script, you're setting the custom properties on the body element. However, in your stylesheet, your custom properties are all (as usual) specified for :root, the html element. So the value of --global-primary-colour-hue is unchanged for :root, and the value of --global-primary-colour in turn remains unchanged. This unchanged value then gets inherited by body and .box — the new value of --global-primary-colour-hue ends up never getting used.

Setting the property for document.documentElement in your script, or changing the CSS rule to target body instead, allows your code to work correctly without needing that last line:

var element = document.getElementById("hue-range");element.onchange = function(){  document.documentElement.style.setProperty(    "--global-primary-colour-hue",     this.value);}
:root {  --global-primary-colour-hue: 211;  --global-primary-colour-saturation: 100%;  --global-primary-colour-lightness: 50%;  --global-primary-colour-opacity: 1;  --global-primary-colour: hsla(    var(--global-primary-colour-hue),    var(--global-primary-colour-saturation),    var(--global-primary-colour-lightness),    var(--global-primary-colour-opacity));}
.box { background-color: var(--global-primary-colour); height: 100px; width: 100px;}
<input id="hue-range" value="0" type="range" min="0" max="360">
<div class="box"></div>

CSS variables: input:focus doesn't set variable

The new CSS pseudo-class :focus-within would be your best shot to achieve this.

The :focus-within pseudo-class matches elements that either match :focus themselfves or that have child which match :focus.