--- gradient-linear-angled ---
// Test gradients with direction.
#set page(width: 90pt)
#grid(
  gutter: 3pt,
  columns: 4,
  ..range(0, 360, step: 15).map(i => box(
    height: 15pt,
    width: 15pt,
    fill: gradient.linear(angle: i * 1deg, (red, 0%), (blue, 100%)),
  ))
)


--- gradient-linear-oklab ---
// The tests below test whether hue rotation works correctly.
// Here we test in Oklab space for reference.
#set page(
  width: 100pt,
  height: 30pt,
  fill: gradient.linear(red, purple, space: oklab)
)

--- gradient-linear-oklch ---
// Test in OkLCH space.
#set page(
  width: 100pt,
  height: 30pt,
  fill: gradient.linear(red, purple, space: oklch)
)

--- gradient-linear-hsv ---
// Test in HSV space.
#set page(
  width: 100pt,
  height: 30pt,
  fill: gradient.linear(red, purple, space: color.hsv)
)

--- gradient-linear-hsl ---
// Test in HSL space.
#set page(
  width: 100pt,
  height: 30pt,
  fill: gradient.linear(red, purple, space: color.hsl)
)

--- gradient-linear-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the page and the rectangles.
#let grad = gradient.linear(red, blue, green, purple, relative: "parent")
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))

--- gradient-linear-relative-self ---
// The image should look as if there are multiple gradients, one for each
// rectangle.
#let grad = gradient.linear(red, blue, green, purple, relative: "self")
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))

--- gradient-linear-relative-parent-block ---
// The image should look as if there are two nested gradients, one for the page
// and one for a nested block. The rotated rectangles are not visible because
// they are relative to the block.
#let grad = gradient.linear(red, blue, green, purple, relative: "parent")
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#block(
  width: 40pt,
  height: 40pt,
  inset: 2.5pt,
  fill: grad,
)[
  #place(top + right, my-rect)
  #place(bottom + center, rotate(45deg, my-rect))
]

--- gradient-linear-repeat-and-mirror-1 ---
// Test repeated gradients.
#rect(
  height: 40pt,
  width: 100%,
  fill: gradient.linear(..color.map.inferno).repeat(2, mirror: true)
)

--- gradient-linear-repeat-and-mirror-2 ---
#rect(
  height: 40pt,
  width: 100%,
  fill: gradient.linear(..color.map.rainbow).repeat(2, mirror: true),
)

--- gradient-linear-repeat-and-mirror-3 ---
#rect(
  height: 40pt,
  width: 100%,
  fill: gradient.linear(..color.map.rainbow).repeat(5, mirror: true)
)

--- gradient-linear-sharp-and-repeat ---
#rect(
  height: 40pt,
  width: 100%,
  fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: false)
)

--- gradient-linear-sharp-repeat-and-mirror ---
#rect(
  height: 40pt,
  width: 100%,
  fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: true)
)

--- gradient-linear-sharp ---
#square(
  size: 100pt,
  fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10),
)
#square(
  size: 100pt,
  fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10),
)
#square(
  size: 100pt,
  fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10),
)

--- gradient-linear-sharp-and-smooth ---
#square(
  size: 100pt,
  fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)
#square(
  size: 100pt,
  fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)
#square(
  size: 100pt,
  fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)

--- gradient-linear-stroke ---
#align(center + top, square(size: 50pt, fill: black, stroke: 5pt + gradient.linear(red, blue)))

--- gradient-fill-and-stroke ---
#align(
  center + bottom,
  square(
    size: 50pt,
    fill: gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)),
    stroke: 10pt + gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%))
  )
)

--- gradient-linear-stroke-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the circle stroke and the block fill.
#align(
  center + horizon,
  block(
    width: 50pt,
    height: 50pt,
    fill: gradient.linear(red, blue).sharp(4),
    circle(
      radius: 18pt,
      stroke: 5pt + gradient.linear(red, blue, relative: "parent").sharp(4),
    )
  )
)

--- gradient-linear-line ---
// Test gradient on lines
#set page(width: 100pt, height: 100pt)
#line(length: 100%, stroke: 1pt + gradient.linear(red, blue))
#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue))
#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue, relative: "parent"))

--- gradient-radial-hsl ---
#square(
  size: 100pt,
  fill: gradient.radial(..color.map.rainbow, space: color.hsl),
)

--- gradient-radial-center ---
#grid(
  columns: 2,
  square(
    size: 50pt,
    fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 0%)),
  ),
  square(
    size: 50pt,
    fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 100%)),
  ),
  square(
    size: 50pt,
    fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 0%)),
  ),
  square(
    size: 50pt,
    fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 100%)),
  ),
)

--- gradient-radial-radius ---
#square(
  size: 50pt,
  fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 10%),
)
#square(
  size: 50pt,
  fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 72%),
)

--- gradient-radial-focal-center-and-radius ---
#circle(
  radius: 25pt,
  fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (35%, 35%), focal-radius: 5%),
)
#circle(
  radius: 25pt,
  fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (75%, 35%), focal-radius: 5%),
)

--- gradient-radial-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the page and the rectangles.
#let grad = gradient.radial(red, blue, green, purple, relative: "parent");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))

--- gradient-radial-relative-self ---
// The image should look as if there are multiple gradients, one for each
// rectangle.
#let grad = gradient.radial(red, blue, green, purple, relative: "self");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))

--- gradient-radial-text ---
// Test that gradient fills on text.
// The solid bar gradients are used to make sure that all transforms are
// correct: if you can see the text through the bar, then the gradient is
// misaligned to its reference container.
#set page(width: 200pt, height: auto, margin: 10pt)
#set par(justify: true)
#set text(fill: gradient.radial(red, blue))
#lorem(30)

--- gradient-conic ---
#square(
  size: 50pt,
  fill: gradient.conic(..color.map.rainbow, space: color.hsv),
)

--- gradient-conic-center-shifted-1 ---
#square(
  size: 50pt,
  fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (10%, 10%)),
)

--- gradient-conic-center-shifted-2 ---
#square(
  size: 50pt,
  fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (90%, 90%)),
)

--- gradient-conic-angled ---
#square(
  size: 50pt,
  fill: gradient.conic(..color.map.rainbow, space: color.hsv, angle: 90deg),
)

--- gradient-conic-oklab ---
// Test in Oklab space for reference.
#set page(
  width: 100pt,
  height: 100pt,
  fill: gradient.conic(red, purple, space: oklab)
)

--- gradient-conic-oklch ---
// Test in OkLCH space.
#set page(
  width: 100pt,
  height: 100pt,
  fill: gradient.conic(red, purple, space: oklch)
)

--- gradient-conic-hsv ---
// Test in HSV space.
#set page(
  width: 100pt,
  height: 100pt,
  fill: gradient.conic(red, purple, space: color.hsv)
)

--- gradient-conic-hsl ---
// Test in HSL space.
#set page(
  width: 100pt,
  height: 100pt,
  fill: gradient.conic(red, purple, space: color.hsl)
)

--- gradient-conic-relative-parent ---
// The image should look as if there is a single gradient that is being used for
// both the page and the rectangles.
#let grad = gradient.conic(red, blue, green, purple, relative: "parent");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))

--- gradient-conic-relative-self ---
// The image should look as if there are multiple gradients, one for each
// rectangle.
#let grad = gradient.conic(red, blue, green, purple, relative: "self");
#let my-rect = rect(width: 50%, height: 50%, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
  fill: grad,
  background: place(top + left, my-rect),
)
#place(top + right, my-rect)
#place(bottom + center, rotate(45deg, my-rect))

--- gradient-conic-stroke ---
#align(
  center + bottom,
  square(
    size: 50pt,
    fill: black,
    stroke: 10pt + gradient.conic(red, blue)
  )
)

--- gradient-conic-text ---
#set page(width: 200pt, height: auto, margin: 10pt)
#set par(justify: true)
#set text(fill: gradient.conic(red, blue, angle: 45deg))
#lorem(30)

--- gradient-text-bad-relative ---
// Make sure they don't work when `relative: "self"`.
// Hint: 17-61 make sure to set `relative: auto` on your text fill
// Error: 17-61 gradients and tilings on text must be relative to the parent
#set text(fill: gradient.linear(red, blue, relative: "self"))

--- gradient-text-global ---
// Test that gradient fills on text work for globally defined gradients.
#set page(width: 200pt, height: auto, margin: 10pt, background: {
  rect(width: 100%, height: 30pt, fill: gradient.linear(red, blue))
})
#set par(justify: true)
#set text(fill: gradient.linear(red, blue))
#lorem(30)

--- gradient-text-dir ---
// Sanity check that the direction works on text.
#set page(width: 200pt, height: auto, margin: 10pt, background: {
  rect(height: 100%, width: 30pt, fill: gradient.linear(dir: btt, red, blue))
})
#set par(justify: true)
#set text(fill: gradient.linear(dir: btt, red, blue))
#lorem(30)

--- gradient-text-in-container ---
// Test that gradient fills on text work for locally defined gradients.
#set page(width: auto, height: auto, margin: 10pt)
#show box: set text(fill: gradient.linear(..color.map.rainbow))
Hello, #box[World]!

--- gradient-text-rotate ---
// Test that gradients fills on text work with transforms.
#set page(width: auto, height: auto, margin: 10pt)
#show box: set text(fill: gradient.linear(..color.map.rainbow))
#rotate(45deg, box[World])

--- gradient-text-decoration ---
#set text(fill: gradient.linear(red, blue))

Hello #underline[World]! \
Hello #overline[World]! \
Hello #strike[World]! \

--- gradient-transformed ---
// Test whether gradients work well when they are contained within a transform.
#let grad = gradient.linear(red, blue, green, purple, relative: "parent");
#let my-rect = rect(width: 50pt, height: 50pt, fill: grad)
#set page(
  height: 50pt,
  width: 50pt,
  margin: 2.5pt,
)
#place(top + right, scale(x: 200%, y: 130%, my-rect))
#place(bottom + center, rotate(45deg, my-rect))
#place(horizon + center, scale(x: 200%, y: 130%, rotate(45deg, my-rect)))

--- gradient-presets ---
// Test all gradient presets.
#set page(width: 100pt, height: auto, margin: 0pt)
#set text(fill: white, size: 18pt)
#set text(top-edge: "bounds", bottom-edge: "bounds")

#let presets = (
  ("turbo", color.map.turbo),
  ("cividis", color.map.cividis),
  ("rainbow", color.map.rainbow),
  ("spectral", color.map.spectral),
  ("viridis", color.map.viridis),
  ("inferno", color.map.inferno),
  ("magma", color.map.magma),
  ("plasma", color.map.plasma),
  ("rocket", color.map.rocket),
  ("mako", color.map.mako),
  ("vlag", color.map.vlag),
  ("icefire", color.map.icefire),
  ("flare", color.map.flare),
  ("crest", color.map.crest),
)

#stack(
  spacing: 3pt,
  ..presets.map(((name, preset)) => block(
    width: 100%,
    height: 20pt,
    fill: gradient.linear(..preset),
    align(center + horizon, smallcaps(name)),
  ))
)

// Test that gradients are applied correctly on equations.

--- gradient-math-cancel ---
// Test on cancel
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box

$ a dot cancel(5) = cancel(25) 5 x + cancel(5) 1 $

--- gradient-math-frac ---
// Test on frac
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box

$ nabla dot bold(E) = frac(rho, epsilon_0) $

--- gradient-math-root ---
// Test on root
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box

$ x_"1,2" = frac(-b plus.minus sqrt(b^2 - 4 a c), 2 a) $

--- gradient-math-mat ---
// Test on matrix
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box

$ A = mat(
  1, 2, 3;
  4, 5, 6;
  7, 8, 9
) $

--- gradient-math-underover ---
// Test on underover
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box

$ underline(X^2) $
$ overline("hello, world!") $

--- gradient-math-dir ---
// Test a different direction
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow, dir: ttb))
#show math.equation: box

$ A = mat(
  1, 2, 3;
  4, 5, 6;
  7, 8, 9
) $

$ x_"1,2" = frac(-b plus.minus sqrt(b^2 - 4 a c), 2 a) $

--- gradient-math-misc ---
// Test miscellaneous
#show math.equation: set text(fill: gradient.linear(..color.map.rainbow))
#show math.equation: box

$ hat(x) = bar x bar = vec(x, y, z) = tilde(x) = dot(x) $
$ x prime = vec(1, 2, delim: "[") $
$ sum_(i in NN) 1 + i $
$ attach(
  Pi, t: alpha, b: beta,
  tl: 1, tr: 2+3, bl: 4+5, br: 6,
) $

--- gradient-math-radial ---
// Test radial gradient
#show math.equation: set text(fill: gradient.radial(..color.map.rainbow, center: (30%, 30%)))
#show math.equation: box

$ A = mat(
  1, 2, 3;
  4, 5, 6;
  7, 8, 9
) $

--- gradient-math-conic ---
// Test conic gradient
#show math.equation: set text(fill: gradient.conic(red, blue, angle: 45deg))
#show math.equation: box

$ A = mat(
  1, 2, 3;
  4, 5, 6;
  7, 8, 9
) $


--- gradient-kind ---
// Test gradient functions.
#test(gradient.linear(red, green, blue).kind(), gradient.linear)

--- gradient-stops ---
#test(gradient.linear(red, green, blue).stops(), ((red, 0%), (green, 50%), (blue, 100%)))

--- gradient-sample ---
#test(gradient.linear(red, green, blue, space: rgb).sample(0%), red)
#test(gradient.linear(red, green, blue, space: rgb).sample(25%), rgb("#97873b"))
#test(gradient.linear(red, green, blue, space: rgb).sample(50%), green)
#test(gradient.linear(red, green, blue, space: rgb).sample(75%), rgb("#17a08c"))
#test(gradient.linear(red, green, blue, space: rgb).sample(100%), blue)

--- gradient-space ---
#test(gradient.linear(red, green, space: rgb).space(), rgb)
#test(gradient.linear(red, green, space: oklab).space(), oklab)
#test(gradient.linear(red, green, space: oklch).space(), oklch)
#test(gradient.linear(red, green, space: cmyk).space(), cmyk)
#test(gradient.linear(red, green, space: luma).space(), luma)
#test(gradient.linear(red, green, space: color.linear-rgb).space(), color.linear-rgb)
#test(gradient.linear(red, green, space: color.hsl).space(), color.hsl)
#test(gradient.linear(red, green, space: color.hsv).space(), color.hsv)

--- gradient-relative ---
#test(gradient.linear(red, green, relative: "self").relative(), "self")
#test(gradient.linear(red, green, relative: "parent").relative(), "parent")
#test(gradient.linear(red, green).relative(), auto)

--- gradient-angle ---
#test(gradient.linear(red, green).angle(), 0deg)
#test(gradient.linear(red, green, dir: ltr).angle(), 0deg)
#test(gradient.linear(red, green, dir: rtl).angle(), 180deg)
#test(gradient.linear(red, green, dir: ttb).angle(), 90deg)
#test(gradient.linear(red, green, dir: btt).angle(), 270deg)

--- gradient-repeat ---
#test(
  gradient.linear(red, green, blue).repeat(2).stops(),
  ((red, 0%), (green, 25%), (blue, 50%), (red, 50%), (green, 75%), (blue, 100%))
)
#test(
  gradient.linear(red, green, blue).repeat(2, mirror: true).stops(),
  ((red, 0%), (green, 25%), (blue, 50%), (green, 75%), (red, 100%))
)

--- issue-2902-gradient-oklch-panic ---
// Minimal reproduction of #2902
#set page(width: 15cm, height: auto, margin: 1em)
#set block(width: 100%, height: 1cm, above: 2pt)

// Oklch
#block(fill: gradient.linear(red, purple, space: oklch))
#block(fill: gradient.linear(..color.map.rainbow, space: oklch))
#block(fill: gradient.linear(..color.map.plasma, space: oklch))

--- issue-2902-gradient-oklab-panic ---
#set page(width: 15cm, height: auto, margin: 1em)
#set block(width: 100%, height: 1cm, above: 2pt)

// Oklab
#block(fill: gradient.linear(red, purple, space: oklab))
#block(fill: gradient.linear(..color.map.rainbow, space: oklab))
#block(fill: gradient.linear(..color.map.plasma, space: oklab))

--- issue-gradient-cmyk-encode ---
// Test that CMYK works on gradients
#set page(margin: 0pt, width: 100pt, height: auto)

#let violet = cmyk(75%, 80%, 0%, 0%)
#let blue = cmyk(75%, 30%, 0%, 0%)

#rect(
  width: 100%,
  height: 10pt,
  fill: gradient.linear(violet, blue)
)

#rect(
  width: 100%,
  height: 10pt,
  fill: gradient.linear(rgb(violet), rgb(blue))
)

// In PDF format, this gradient can look different from the others.
// This is because PDF readers do weird things with CMYK.
#rect(
  width: 100%,
  height: 10pt,
  fill: gradient.linear(violet, blue, space: cmyk)
)
