(.module: [library [lux {"-" [All Cursor and static false true]} [control ["[0]" maybe] [parser ["s" code]]] [data ["[0]" color] ["[0]" product] [number ["n" nat] ["i" int] ["r" rev] ["f" frac]] ["[0]" text ["%" format {"+" [Format format]}]] [collection ["[0]" list ("[1]#[0]" functor)]]] [type abstract] [macro ["[0]" template] ["[0]" code] [syntax {"+" [syntax:]}]] [world [net {"+" [URL]}]]]] [// [selector {"+" [Label]}]]) (syntax: (text_identifier [identifier s.text]) (in (list (code.local_identifier (text.replaced "-" "_" identifier))))) (template: (enumeration: + +) (abstract: .public (def: .public (-> ) (|>> :representation)) (`` (template [ ] [(def: .public (:abstraction ))] (~~ (template.spliced +)) )) (template.spliced +))) (template: (multi: ) (def: .public ( pre post) (-> (Value ) (Value ) (Value )) (:abstraction (format (:representation pre) (:representation post))))) (def: (%number value) (Format Frac) (let [raw (%.frac value)] (if (f.< +0.0 value) raw (|> raw (text.split_at 1) maybe.trusted product.right)))) (abstract: .public (Value brand) Text (def: .public value (-> (Value Any) Text) (|>> :representation)) (template [ ] [(def: .public Value (:abstraction ))] [initial "initial"] [inherit "inherit"] [unset "unset"] ) (template [ + +] [(abstract: .public Any) (`` (template [ ] [(def: .public (Value ) (:abstraction ))] (~~ (template.spliced +)))) (with_expansions [ (template.spliced +)] (template [] [(`` (def: .public (~~ (..text_identifier )) (Value ) (:abstraction )))] ))] [All [] []] [Number [] []] [Length [] []] [Time [] []] [Thickness [] [["medium"] ["thin"] ["thick"]]] [Slice [[full_slice "fill"]] []] [Alignment [[auto_alignment "auto"]] [["stretch"] ["center"] ["flex-start"] ["flex-end"] ["baseline"] ["space-between"] ["space-around"]]] [Animation [] []] [Animation_Direction [[normal_direction "normal"]] [["reverse"] ["alternate"] ["alternate-reverse"]]] [Animation_Fill [[fill_forwards "forwards"] [fill_backwards "backwards"] [fill_both "both"]] []] [Column_Fill [] [["balance"] ["auto"]]] [Column_Span [] [["all"]]] [Iteration [] [["infinite"]]] [Count [] []] [Play [] [["paused"] ["running"]]] [Timing [] [["linear"] ["ease"] ["ease-in"] ["ease-out"] ["ease-in-out"] ["step-start"] ["step-end"]]] [Visibility [[invisible "hidden"] [collapse_visibility "collapse"]] [["visible"]]] [Attachment [[scroll_attachment "scroll"] [fixed_attachment "fixed"] [local_attachment "local"]] []] [Blend [[normal_blend "normal"]] [["multiply"] ["screen"] ["overlay"] ["darken"] ["lighten"] ["color-dodge"] ["color-burn"] ["difference"] ["exclusion"] ["hue"] ["saturation"] ["color"] ["luminosity"]]] [Span [] [["border-box"] ["padding-box"] ["content-box"]]] [Image [[no_image "none"]] []] [Repeat [[stretch_repeat "stretch"]] [["repeat"] ["repeat-x"] ["repeat-y"] ["no-repeat"] ["space"] ["round"]]] [Location [[left_top "left top"] [left_center "left center"] [left_bottom "left bottom"] [right_top "right top"] [right_center "right center"] [right_bottom "right bottom"] [center_top "center top"] [center_center "center center"] [center_bottom "center bottom"]] []] [Fit [[no_fit "none"]] [["fill"] ["cover"] ["contain"] ["scale-down"]]] [Border [] [["hidden"] ["dotted"] ["dashed"] ["solid"] ["double"] ["groove"] ["ridge"] ["inset"] ["outset"]]] [Collapse [] [["separate"] ["collapse"]]] [Box_Decoration_Break [] [["slice"] ["clone"]]] [Caption [] [["top"] ["bottom"]]] [Float [[float_left "left"] [float_right "right"]] []] [Clear [[clear_left "left"] [clear_right "right"] [clear_both "both"]] []] [Counter [] []] [Content [] [["open-quote"] ["close-quote"] ["no-open-quote"] ["no-close-quote"]]] [Cursor [[horizontal_text "text"] [no_cursor "none"]] [["alias"] ["all-scroll"] ["cell"] ["context-menu"] ["col-resize"] ["copy"] ["crosshair"] ["default"] ["e-resize"] ["ew-resize"] ["grab"] ["grabbing"] ["help"] ["move"] ["n-resize"] ["ne-resize"] ["nesw-resize"] ["ns-resize"] ["nw-resize"] ["nwse-resize"] ["no-drop"] ["not-allowed"] ["pointer"] ["progress"] ["row-resize"] ["s-resize"] ["se-resize"] ["sw-resize"] ["vertical-text"] ["w-resize"] ["wait"] ["zoom-in"] ["zoom-out"]]] [Shadow [] []] [Clip [] []] [Text_Direction [[left_to_right "ltr"] [right_to_left "rtl"]] []] [Display [[grid_display "grid"] [no_display "none"]] [["inline"] ["block"] ["contents"] ["flex"] ["inline-block"] ["inline-flex"] ["inline-grid"] ["inline-table"] ["list-item"] ["run-in"] ["table"] ["table-caption"] ["table-column-group"] ["table-header-group"] ["table-footer-group"] ["table-row-group"] ["table-cell"] ["table-column"] ["table-row"]]] [Empty [] [["show"] ["hide"]]] [Filter [] []] [Flex_Direction [] [["row"] ["row-reverse"] ["column"] ["column-reverse"]]] [Flex_Wrap [[no_wrap "nowrap"]] [["wrap"] ["wrap_reverse"]]] [Font_Kerning [[auto_kerning "auto"] [normal_kerning "normal"] [no_kerning "none"]] []] [Font_Size [[medium_size "medium"] [xx_small_size "xx-small"] [x_small_size "x-small"] [small_size "small"] [large_size "large"] [x_large_size "x-large"] [xx_large_size "xx-large"] [smaller_size "smaller"] [larger_size "larger"]] []] [Font_Stretch [[normal_stretch "normal"]] [["condensed"] ["ultra-condensed"] ["extra-condensed"] ["semi-condensed"] ["expanded"] ["semi-expanded"] ["extra-expanded"] ["ultra-expanded"]]] [Font_Style [[normal_style "normal"]] [["italic"] ["oblique"]]] [Font_Weight [[normal_weight "normal"] [weight_100 "100"] [weight_200 "200"] [weight_300 "300"] [weight_400 "400"] [weight_500 "500"] [weight_600 "600"] [weight_700 "700"] [weight_800 "800"] [weight_900 "900"]] [["bold"]]] [Font_Variant [[normal_font "normal"]] [["small-caps"]]] [Grid [] []] [Grid_Content [[auto_content "auto"]] [["max-content"] ["min-content"]]] [Grid_Flow [[row_flow "row"] [column_flow "column"] [dense_flow "dense"] [row_dense_flow "row dense"] [column_dense_flow "column dense"]] []] [Grid_Span [[auto_span "auto"]] []] [Grid_Template [] []] [Hanging_Punctuation [[no_hanging_punctuation "none"]] [["first"] ["last"] ["allow-end"] ["force-end"]]] [Hyphens [[no_hyphens "none"] [manual_hyphens "manual"] [auto_hyphens "auto"]] []] [Orientation [] [["portrait"] ["landscape"]]] [Resolution [] []] [Scan [] [["interlace"] ["progressive"]]] [Boolean [[false "0"] [true "1"]] []] [Update [[no_update "none"] [slow_update "slow"] [fast_update "fast"]] []] [Block_Overflow [[no_block_overflow "none"] [scroll_block_overflow "scroll"] [optional_paged_block_overflow "optional-paged"] [paged_block_overflow "paged"]] []] [Inline_Overflow [[no_inline_overflow "none"] [scroll_inline_overflow "scroll"]] []] [Display_Mode [] [["fullscreen"] ["standalone"] ["minimal-ui"] ["browser"]]] [Color_Gamut [] [["srgb"] ["p3"] ["rec2020"]]] [Inverted_Colors [[no_inverted_colors "none"] [inverted_colors "inverted"]] []] [Pointer [[no_pointer "none"] [coarse_pointer "coarse"] [fine_pointer "fine"]] []] [Hover [[no_hover "none"]] [["hover"]]] [Light [[dim_light "dim"] [normal_light "normal"] [washed_light "washed"]] []] [Ratio [] []] [Scripting [[no_scripting "none"] [initial_scripting_only "initial-only"] [scripting_enabled "enabled"]] []] [Motion [[no_motion_preference "no-preference"] [reduced_motion "reduce"]] []] [Color_Scheme [[no_color_scheme_preference "no-preference"] [light_color_scheme "light"] [dark_color_scheme "dark"]] []] [Isolation [[auto_isolation "auto"]] [["isolate"]]] [List_Style_Position [] [["inside"] ["outside"]]] [List_Style_Type [[no_list_style "none"]] [["disc"] ["armenian"] ["circle"] ["cjk-ideographic"] ["decimal"] ["decimal-leading-zero"] ["georgian"] ["hebrew"] ["hiragana"] ["hiragana-iroha"] ["katakana"] ["katakana-iroha"] ["lower-alpha"] ["lower-greek"] ["lower-latin"] ["lower-roman"] ["square"] ["upper-alpha"] ["upper-greek"] ["upper-latin"] ["upper-roman"]]] [Color [] []] [Overflow [[visible_overflow "visible"] [hidden_overflow "hidden"] [scroll_overflow "scroll"] [auto_overflow "auto"]] []] [Page_Break [[auto_page_break "auto"] [always_page_break "always"] [avoid_page_break "avoid"] [left_page_break "left"] [right_page_break "right"]] []] [Pointer_Events [[auto_pointer_events "auto"] [no_pointer_events "none"]] []] [Position [] [["static"] ["absolute"] ["fixed"] ["relative"] ["sticky"]]] [Quotes [[no_quotes "none"]] []] [Resize [[resize_none "none"] [resize_both "both"] [resize_horizontal "horizontal"] [resize_vertical "vertical"]] []] [Scroll_Behavior [[auto_scroll_behavior "auto"] [smooth_scroll_behavior "smooth"]] []] [Table_Layout [[auto_table_layout "auto"] [fixed_table_layout "fixed"]] []] [Text_Align [[left_text_align "left"] [right_text_align "right"] [center_text_align "center"] [justify_text_align "justify"]] []] [Text_Align_Last [[auto_text_align_last "auto"] [left_text_align_last "left"] [right_text_align_last "right"] [center_text_align_last "center"] [justify_text_align_last "justify"] [start_text_align_last "start"] [end_text_align_last "end"]] []] [Text_Decoration_Line [[no_text_decoration_line "none"] [underline_text_decoration_line "underline"] [overline_text_decoration_line "overline"] [line_through_text_decoration_line "line-through"]] []] [Text_Decoration_Style [[solid_text_decoration_style "solid"] [double_text_decoration_style "double"] [dotted_text_decoration_style "dotted"] [dashed_text_decoration_style "dashed"] [wavy_text_decoration_style "wavy"]] []] [Text_Justification [[auto_text_justification "auto"] [inter_word_text_justification "inter-word"] [inter_character_text_justification "inter-character"] [no_text_justification "none"]] []] [Text_Overflow [[clip_text_overflow "clip"] [ellipsis_text_overflow "ellipsis"]] []] [Text_Transform [[no_text_transform "none"]] [["capitalize"] ["uppercase"] ["lowercase"]]] [Transform [[no_transform "none"]] []] [Transform_Origin [] []] [Transform_Style [] [["flat"] ["preserve_3d"]]] [Transition [[transition_none "none"] [transition_all "all"]] []] [Bidi [[bidi_normal "normal"] [bidi_embed "embed"] [bidi_isolate "isolate"] [bidi_isolate_override "isolate-override"] [bidi_plaintext "plaintext"]] [["bidi-override"]]] [User_Select [[user_select_auto "auto"] [user_select_none "none"] [user_select_text "text"] [user_select_all "all"]] []] [Vertical_Align [[vertical_align_baseline "baseline"] [vertical_align_sub "sub"] [vertical_align_super "super"] [vertical_align_top "top"] [vertical_align_text_top "text-top"] [vertical_align_middle "middle"] [vertical_align_bottom "bottom"] [vertical_align_text_bottom "text-bottom"]] []] [White_Space [[normal_white_space "normal"] [no_wrap_white_space "nowrap"] [pre_white_space "pre"] [pre_line_white_space "pre-line"] [pre_wrap_white_space "pre-wrap"]] []] [Word_Break [[normal_word_break "normal"]] [["break-all"] ["keep-all"] ["break-word"]]] [Word_Wrap [[normal_word_wrap "normal"] [break_word_word_wrap "break-word"]] []] [Writing_Mode [[top_to_bottom_writing_mode "horizontal-tb"] [left_to_right_writing_mode "vertical-rl"] [right_to_left_writing_mode "vertical-lr"]] []] [Z_Index [] []] ) (def: value_separator ",") (def: (apply name inputs) (-> Text (List Text) Value) (|> inputs (text.interposed ..value_separator) (text.enclosed ["(" ")"]) (format name) :abstraction)) (enumeration: Step Text step [[start "start"] [end "end"]] []) (def: .public (steps intervals step) (-> Nat Step (Value Timing)) (..apply "steps" (list (%.nat intervals) (..step step)))) (def: .public (cubic_bezier p0 p1 p2 p3) (-> Frac Frac Frac Frac (Value Timing)) (|> (list p0 p1 p2 p3) (list#each %number) (..apply "cubic-bezier"))) (template [ ] [(def: .public (-> Nat (Value )) (|>> %.nat :abstraction))] [iteration Iteration] [count Count] [slice_number/1 Slice] [span_line Grid_Span] ) (def: .public animation (-> Label (Value Animation)) (|>> :abstraction)) (def: .public (rgb color) (-> color.Color (Value Color)) (let [[red green blue] (color.rgb color)] (..apply "rgb" (list (%.nat red) (%.nat green) (%.nat blue))))) (def: .public (rgba pigment) (-> color.Pigment (Value Color)) (let [(^slots [color.#color color.#alpha]) pigment [red green blue] (color.rgb color)] (..apply "rgba" (list (%.nat red) (%.nat green) (%.nat blue) (if (r.= (# r.interval top) alpha) "1.0" (format "0" (%.rev alpha))))))) (template [ ] [(def: .public ( value) (-> Frac (Value Length)) (:abstraction (format (%number value) )))] [em "em"] [ex "ex"] [rem "rem"] [ch "ch"] [vw "vw"] [vh "vh"] [vmin "vmin"] [vmax "vmax"] [% "%"] [cm "cm"] [mm "mm"] [in "in"] [px "px"] [pt "pt"] [pc "pc"] [fr "fr"] ) (def: (%int value) (Format Int) (if (i.< +0 value) (%.int value) (%.nat (.nat value)))) (template [ ] [(def: .public ( value) (-> Int (Value Time)) (:abstraction (format (if (i.< +0 value) (%.int value) (%.nat (.nat value))) )))] [seconds "s"] [milli_seconds "ms"] ) (def: .public thickness (-> (Value Length) (Value Thickness)) (|>> :transmutation)) (def: slice_separator " ") (def: .public (slice_number/2 horizontal vertical) (-> Nat Nat (Value Slice)) (:abstraction (format (%.nat horizontal) ..slice_separator (%.nat vertical)))) (abstract: .public Stop Text (def: .public stop (-> (Value Color) Stop) (|>> (:representation Value) (:abstraction Stop))) (def: stop_separator " ") (def: .public (single_stop length color) (-> (Value Length) (Value Color) Stop) (:abstraction (format (:representation Value color) ..stop_separator (:representation Value length)))) (def: .public (double_stop start end color) (-> (Value Length) (Value Length) (Value Color) Stop) (:abstraction (format (:representation Value color) ..stop_separator (:representation Value start) ..stop_separator (:representation Value end)))) (abstract: .public Hint Text (def: .public hint (-> (Value Length) Hint) (|>> (:representation Value) (:abstraction Hint))) (def: (with_hint [hint stop]) (-> [(Maybe Hint) Stop] Text) (case hint {.#None} (:representation Stop stop) {.#Some hint} (format (:representation Hint hint) ..value_separator (:representation Stop stop)))))) (type: .public (List/1 a) [a (List a)]) (abstract: .public Angle Text (def: .public angle (-> Angle Text) (|>> :representation)) (def: .public (turn value) (-> Rev Angle) (:abstraction (format (%.rev value) "turn"))) (def: degree_limit Nat 360) (def: .public (degree value) (-> Nat Angle) (:abstraction (format (%.nat (n.% ..degree_limit value)) "deg"))) (template [ ] [(def: .public Angle (..degree ))] [000 to_top] [090 to_right] [180 to_bottom] [270 to_left] ) (template [ ] [(def: .public ( angle start next) (-> Angle Stop (List/1 [(Maybe Hint) Stop]) (Value Image)) (let [[now after] next] (..apply (list& (:representation Angle angle) (with_hint now) (list#each with_hint after)))))] [linear_gradient "linear-gradient"] [repeating_linear_gradient "repeating-linear-gradient"] ) ) (abstract: .public Percentage Text (def: .public percentage (-> Percentage Text) (|>> :representation)) (def: percentage_limit Nat (.++ 100)) (def: .public (%% value) (-> Nat Percentage) (:abstraction (format (%.nat (n.% percentage_limit value)) "%"))) (def: .public slice_percent/1 (-> Percentage (Value Slice)) (|>> :representation (:abstraction Value))) (def: .public (slice_percent/2 horizontal vertical) (-> Percentage Percentage (Value Slice)) (:abstraction Value (format (:representation horizontal) ..slice_separator (:representation vertical)))) (template [
 +]
      [(`` (template [ ]
             [(def: .public 
                (->  (Value Filter))
                (|>> 
 (list) (..apply )))]

             (~~ (template.spliced +))))]

      [Nat (<| (:representation Value) ..px n.frac)
       [[blur "blur"]]]
      [Nat (<| ..angle ..degree)
       [[hue_rotate "hue-rotate"]]]
      [Percentage (:representation Percentage)
       [[brightness "brightness"]
        [contrast "contrast"]
        [grayscale "grayscale"]
        [invert "invert"]
        [opacity "opacity"]
        [saturate "saturate"]
        [sepia "sepia"]]]
      )
    )

  (def: .public svg_filter
    (-> URL (Value Filter))
    (|>> (list) (..apply "url")))

  (def: default_shadow_length (px +0.0))

  (def: .public (drop_shadow horizontal vertical blur spread color)
    (-> (Value Length) (Value Length)
        (Maybe (Value Length)) (Maybe (Value Length))
        (Value Color)
        (Value Filter))
    (|> (list (:representation horizontal)
              (:representation vertical)
              (|> blur (maybe.else ..default_shadow_length) :representation)
              (|> spread (maybe.else ..default_shadow_length) :representation)
              (:representation color))
        (text.interposed " ")
        (list)
        (..apply "drop-shadow")))

  (def: length_separator " ")

  (template [ ]
    [(def: .public ( horizontal vertical)
       (-> (Value Length) (Value Length) (Value ))
       (:abstraction (format (:representation horizontal)
                             ..length_separator
                             (:representation vertical))))]

    [location Location]
    [fit Fit]
    )

  (def: .public (fit/1 length)
    (-> (Value Length) (Value Fit))
    (..fit length length))

  (def: .public image
    (-> URL (Value Image))
    (|>> %.text
         (list)
         (..apply "url")))

  (enumeration: Shape Text
    shape
    [[ellipse_shape "ellipse"]
     [circle_shape "circle"]]
    [])

  (enumeration: Extent Text
    extent
    [[closest_side "closest-side"]
     [closest_corner "closest-corner"]
     [farthest_side "farthest-side"]
     [farthest_corner "farthest-corner"]]
    [])

  (template [ ]
    [(def: .public ( shape extent location start next)
       (-> Shape (Maybe Extent) (Value Location)
           Stop (List/1 [(Maybe Hint) Stop])
           (Value Image))
       (let [after_extent (format "at " (:representation location))
             with_extent (case extent
                           {.#Some extent}
                           (format (..extent extent) " " after_extent)
                           
                           {.#None}
                           after_extent)
             where (format (..shape shape) " " with_extent)
             [now after] next]
         (..apply  (list& (..shape shape)
                                    (with_hint now)
                                    (list#each with_hint after)))))]
    
    [radial_gradient "radial-gradient"]
    [repeating_radial_gradient "repeating-radial-gradient"]
    )

  (def: .public (shadow horizontal vertical blur spread color inset?)
    (-> (Value Length) (Value Length)
        (Maybe (Value Length)) (Maybe (Value Length))
        (Value Color) Bit
        (Value Shadow))
    (let [with_inset (if inset?
                       (list "inset")
                       (list))]
      (|> (list& (:representation horizontal)
                 (:representation vertical)
                 (|> blur (maybe.else ..default_shadow_length) :representation)
                 (|> spread (maybe.else ..default_shadow_length) :representation)
                 (:representation color)
                 with_inset)
          (text.interposed " ")
          :abstraction)))

  (type: .public Rectangle
    (Record
     [#top (Value Length)
      #right (Value Length)
      #bottom (Value Length)
      #left (Value Length)]))

  (def: .public (clip rectangle)
    (-> Rectangle (Value Clip))
    (`` (..apply "rect" (list (~~ (template []
                                    [(:representation (value@  rectangle))]

                                    [#top] [#right] [#bottom] [#left]))))))

  (def: .public counter
    (-> Label (Value Counter))
    (|>> :abstraction))

  (def: .public current_count
    (-> (Value Counter) (Value Content))
    (|>> :representation (list) (..apply "counter")))

  (def: .public text
    (-> Text (Value Content))
    (|>> %.text :abstraction))

  (def: .public attribute
    (-> Label (Value Content))
    (|>> (list) (..apply "attr")))

  (def: .public media
    (-> URL (Value Content))
    (|>> (list) (..apply "url")))

  (enumeration: Font Text
    font_name
    [[serif "serif"]
     [sans_serif "sans-serif"]
     [cursive "cursive"]
     [fantasy "fantasy"]
     [monospace "monospace"]]
    [(def: .public font
       (-> Text Font)
       (|>> %.text :abstraction))

     (def: .public (font_family options)
       (-> (List Font) (Value Font))
       (case options
         {.#Item _}
         (|> options
             (list#each ..font_name)
             (text.interposed ",")
             (:abstraction Value))
         
         {.#End}
         ..initial))])

  (def: .public font_size
    (-> (Value Length) (Value Font_Size))
    (|>> :transmutation))

  (def: .public number
    (-> Frac (Value Number))
    (|>> %number :abstraction))

  (def: .public grid
    (-> Label (Value Grid))
    (|>> :abstraction))

  (def: .public fit_content
    (-> (Value Length) (Value Grid_Content))
    (|>> :representation (list) (..apply "fit-content")))

  (def: .public (min_max min max)
    (-> (Value Grid_Content) (Value Grid_Content) (Value Grid_Content))
    (..apply "minmax" (list (:representation min)
                            (:representation max))))

  (def: .public grid_span
    (-> Nat (Value Grid_Span))
    (|>> %.nat (format "span ") :abstraction))

  (def: grid_column_separator " ")
  (def: grid_row_separator " ")

  (def: .public grid_template
    (-> (List (List (Maybe (Value Grid)))) (Value Grid_Template))
    (let [empty (: (Value Grid)
                   (:abstraction "."))]
      (|>> (list#each (|>> (list#each (|>> (maybe.else empty)
                                           :representation))
                           (text.interposed ..grid_column_separator)
                           (text.enclosed ["'" "'"])))
           (text.interposed ..grid_row_separator)
           :abstraction)))

  (def: .public (resolution dpi)
    (-> Nat (Value Resolution))
    (:abstraction (format (%.nat dpi) "dpi")))

  (def: .public (ratio numerator denominator)
    (-> Nat Nat (Value Ratio))
    (:abstraction (format (%.nat numerator) "/" (%.nat denominator))))

  (enumeration: Quote Text
    quote_text
    [[double_quote "\0022"]
     [single_quote "\0027"]
     [single_left_angle_quote "\2039"]
     [single_right_angle_quote "\203A"]
     [double_left_angle_quote "\00AB"]
     [double_right_angle_quote "\00BB"]
     [single_left_quote "\2018"]
     [single_right_quote "\2019"]
     [double_left_quote "\201C"]
     [double_right_quote "\201D"]
     [low_double_quote "\201E"]]
    [(def: .public quote
       (-> Text Quote)
       (|>> :abstraction))])

  (def: quote_separator " ")

  (def: .public (quotes [left0 right0] [left1 right1])
    (-> [Quote Quote] [Quote Quote] (Value Quotes))
    (|> (list left0 right0 left1 right1)
        (list#each (|>> ..quote_text %.text))
        (text.interposed ..quote_separator)
        :abstraction))

  (def: .public (matrix_2d [a b] [c d] [tx ty])
    (-> [Frac Frac]
        [Frac Frac]
        [Frac Frac]
        (Value Transform))
    (|> (list a b c d tx ty)
        (list#each %number)
        (..apply "matrix")))

  (def: .public (matrix_3d [a0 b0 c0 d0] [a1 b1 c1 d1] [a2 b2 c2 d2] [a3 b3 c3 d3])
    (-> [Frac Frac Frac Frac]
        [Frac Frac Frac Frac]
        [Frac Frac Frac Frac]
        [Frac Frac Frac Frac]
        (Value Transform))
    (|> (list a0 b0 c0 d0 a1 b1 c1 d1 a2 b2 c2 d2 a3 b3 c3 d3)
        (list#each %number)
        (..apply "matrix3d")))

  (template [   ]
    [(`` (def: .public ( [(~~ (template.spliced ))])
           (-> [(~~ (template.spliced ))] (Value Transform))
           (|> (list (~~ (template.spliced )))
               (list#each %number)
               (..apply ))))]

    [translate_2d "translate" [Frac Frac] [x y]]
    [translate_3d "translate3d" [Frac Frac Frac] [x y z]]
    [translate_x "translateX" [Frac] [value]]
    [translate_y "translateY" [Frac] [value]]
    [translate_z "translateZ" [Frac] [value]]

    [scale_2d "scale" [Frac Frac] [x y]]
    [scale_3d "scale3d" [Frac Frac Frac] [x y z]]
    [scale_x "scaleX" [Frac] [value]]
    [scale_y "scaleY" [Frac] [value]]
    [scale_z "scaleZ" [Frac] [value]]

    [perspective "perspective" [Frac] [value]]
    )

  (template [   ]
    [(`` (def: .public ( [(~~ (template.spliced ))])
           (-> [(~~ (template.spliced ))] (Value Transform))
           (|> (list (~~ (template.spliced )))
               (list#each ..angle)
               (..apply ))))]

    [rotate_2d "rotate" [Angle] [angle]]
    [rotate_x "rotateX" [Angle] [angle]]
    [rotate_y "rotateY" [Angle] [angle]]
    [rotate_z "rotateZ" [Angle] [angle]]

    [skew "skew" [Angle Angle] [x_angle y_angle]]
    [skew_x "skewX" [Angle] [angle]]
    [skew_y "skewY" [Angle] [angle]]
    )

  (def: .public (rotate_3d [x y z angle])
    (-> [Frac Frac Frac Angle] (Value Transform))
    (..apply "rotate3d"
             (list (%number x) (%number y) (%number z) (..angle angle))))

  (def: origin_separator " ")

  (def: .public (origin_2d x y)
    (-> (Value Length) (Value Length) (Value Transform_Origin))
    (:abstraction (format (:representation x) ..origin_separator
                          (:representation y))))

  (def: .public (origin_3d x y z)
    (-> (Value Length) (Value Length) (Value Length) (Value Transform_Origin))
    (:abstraction (format (:representation x) ..origin_separator
                          (:representation y) ..origin_separator
                          (:representation z))))

  (def: .public vertical_align
    (-> (Value Length) (Value Vertical_Align))
    (|>> :transmutation))

  (def: .public (z_index index)
    (-> Int (Value Z_Index))
    (:abstraction (if (i.< +0 index)
                    (%.int index)
                    (%.nat (.nat index)))))

  (multi: multi_image Image ",")
  (multi: multi_shadow Shadow ",")
  (multi: multi_content Content " ")
  )