123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539(** Border utilities for border styles, widths, and radii
What's included:
- Border widths: `border`, `border-0/2/4/8`, and side/axis variants.
- Border styles: `border-solid/dashed/dotted/double/none` via a CSS var.
- Border radius: `rounded-*` and `rounded-full`.
- Side-specific border radius: `rounded-t-*`, `rounded-r-*`, `rounded-b-*`,
`rounded-l-*` for top/right/bottom/left sides.
- Corner-specific border radius: `rounded-tl-*`, `rounded-tr-*`,
`rounded-br-*`, `rounded-bl-*` for individual corners.
- Outline offsets and simple ring helpers.
Parsing contract (`of_string`):
- Accepts tokens like ["border"], ["border"; "t"], ["rounded"; "md"],
["ring"; "2"], ["outline"; "offset"; "4"]. Unknown tokens yield `Error
(`Msg "Not a border utility")`. *)moduleCss=Cascade.Css(* Which corners a [rounded-*] utility rounds: every corner, one physical or
logical side, or a single corner. *)moduleCorner=structtypet=|All|Start|End|Top|Right|Bottom|Left|Start_start|Start_end|End_end|End_start|Top_left|Top_right|Bottom_right|Bottom_leftend(* Border-radius t-shirt sizes. [Rsz_default] is the bare [rounded] (no size
suffix). [Rsz_arbitrary] carries the bracket inner value. The [Rsz_] prefix
avoids clashing with [Option.None]. *)typerounded_size=|Rsz_none|Rsz_xs|Rsz_sm|Rsz_default|Rsz_md|Rsz_lg|Rsz_xl|Rsz_2xl|Rsz_3xl|Rsz_4xl|Rsz_full|Rsz_themeofstring(* radius named by a project [--radius-*] token (rounded-blob) *)|Rsz_arbitraryofstring*Css.length|Rsz_rawofstring*string(* rounded-[foo]: a corner names its own longhands, so a bracket no length
reader took still reaches them and the value is forwarded verbatim -
Tailwind's token-stream contract. *)moduleHandler=structopenStyleopenCsstypet=|(* Border width utilities *)Border|Border_0|Border_2|Border_4|Border_8|Border_widthofint|Border_width_bracketofstring*Css.border_width|Border_side_width_bracketofstring*string*Css.border_width|(* A [line-width:] hint over a value no width grammar reads
(border-[line-width:red]). The hint chooses the longhand and the value
is forwarded verbatim, which is Tailwind's token-stream contract; the
browser discards the width and keeps the style beside it. *)Border_width_rawofstring*string|Border_side_width_rawofstring*string*string(* a side, physical or logical, and an arbitrary width inner:
border-t-[1px], border-x-[3px] *)|Border_side_widthofstring*int(* side ("t"/"r"/"b"/"l") with a width Tailwind spells in px: border-t-16.
The 0/2/4/8 constructors below keep their own names, as Border_0/2/4/8
do beside Border_width. *)|(* Border side/axis utilities *)Border_t|Border_r|Border_b|Border_l|Border_x|Border_y|Border_x_widthofint|Border_y_widthofint|(* Logical single-side borders: inline/block start/end *)Border_s|Border_e|Border_bs|Border_be|Border_s_widthofint|Border_e_widthofint|Border_bs_widthofint|Border_be_widthofint|(* Border style utilities *)Border_solid|Border_dashed|Border_dotted|Border_double|Border_hidden|Border_none|(* Border radius utilities. One parametric variant over (position, size);
the bare [rounded] is [Rounded (Corner.All, Rsz_default)] and arbitrary
brackets are [Rounded (pos, Rsz_arbitrary inner)]. *)RoundedofCorner.t*rounded_size|(* Outline utilities *)Outline|Outline_0|Outline_widthofint(* outline-1, outline-2, outline-4, outline-8 *)|Outline_width_bracketofstring*Css.border_width(* outline-[12px], outline-[1.5], etc. *)|Outline_width_droppedofstring(* outline-[50%]: a percentage is a width to Tailwind's type inference and
[outline-width] takes none, so the browser keeps only the style
declaration beside it. *)|Outline_width_varofstring(* outline-[length:var(...)], etc. *)|(* A width hint over a value no width grammar reads
(outline-[length:red]), forwarded verbatim like its border twin. *)Outline_width_rawofstring*string(* Outline style utilities (dashed, dotted, etc.) are in
Outline_style_handler *)|Outline_hidden|Outline_offsetofint|Outline_offset_varofstring(* outline-offset-[var(--value)] *)|Outline_offset_arbitraryofstring(* outline-offset-[3px] *)|Outline_offset_rawofstring*string|Neg_outline_offsetofint|Neg_outline_offset_varofstring(* -outline-offset-[var(--value)] *)letname="borders"(* border-width/color/radius sort at priority 19. outline-* (canonical rank
~92) comes much later - after box-shadow and ring (effects, priority 27),
before the filters (priority 30) - so the outline variants return priority
28. *)letpriority=function|Outline|Outline_0|Outline_width_|Outline_width_bracket_|Outline_width_dropped_|Outline_width_var_|Outline_width_raw_|Outline_hidden|Outline_offset_|Outline_offset_var_|Outline_offset_arbitrary_|Outline_offset_raw_|Neg_outline_offset_|Neg_outline_offset_var_->28|_->19(* Create border style variable with @property for utilities that reference
it. Position 6 to match Tailwind's order after translate (0-2) and scale
(3-5). *)letborder_style_var=Var.property_defaultCss.Border_style~initial:(Solid:Css.border_style)~property_order:6~family:`Border"tw-border-style"(* Helper for border utilities that reference the variable with @property
default *)letmake_border_utiladditional_props=letborder_ref=Var.referenceborder_style_varinletproperty_rule=matchVar.property_ruleborder_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule(border_style(Varborder_ref)::additional_props)(* Helper for border style utilities that set the variable *)letborder_style_utilborder_style_value=letdecl=Var.setborder_style_varborder_style_valueinstyle[decl;border_styleborder_style_value]letborder_default?theme()=make_border_util[Css.border_width(Px(float_of_int(Scheme.or_defaulttheme).default_border_width));]letborder_0=make_border_util[Css.border_width(Px0.)]letborder_2=make_border_util[Css.border_width(Px2.)]letborder_4=make_border_util[Css.border_width(Px4.)]letborder_8=make_border_util[Css.border_width(Px8.)]letborder_nn=make_border_util[Css.border_width(Px(float_of_intn))]letborder_width_bracket_stylewidth=make_border_util[Css.border_widthwidth](* Helper for border side utilities that reference the variable with @property
default *)letmake_side_utilside_props_fn=letborder_ref=Var.referenceborder_style_varinletproperty_rule=matchVar.property_ruleborder_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule(side_props_fnborder_ref)(* What one side writes for a width: the border-style variable and the width
itself, on the longhands that side names. The axes paint the logical inline
and block axes through the border-inline and border-block longhands, not
the two physical edges; the logical single sides paint one inline or block
edge each. *)letside_width_propssideborder_var(w:Css.border_width)=matchsidewith|"x"->[border_inline_style(logical_border_style(Varborder_var));border_inline_width(logical_border_widthw);]|"y"->[border_block_style(logical_border_style(Varborder_var));border_block_width(logical_border_widthw);]|"s"->[border_inline_start_style(Varborder_var);border_inline_start_widthw;]|"e"->[border_inline_end_style(Varborder_var);border_inline_end_widthw]|"bs"->[border_block_start_style(Varborder_var);border_block_start_widthw;]|"be"->[border_block_end_style(Varborder_var);border_block_end_widthw]|"t"->[border_top_style(Varborder_var);border_top_widthw]|"r"->[border_right_style(Varborder_var);border_right_widthw]|"b"->[border_bottom_style(Varborder_var);border_bottom_widthw]|_->[border_left_style(Varborder_var);border_left_widthw](* The style declaration a side writes beside its width, and the width
longhand it writes it on. A raw width goes on the same longhand, so the
rule is one declaration the browser drops and one it keeps. *)letside_style_propssideborder_var=matchsidewith|"x"->[border_inline_style(logical_border_style(Varborder_var))]|"y"->[border_block_style(logical_border_style(Varborder_var))]|"s"->[border_inline_start_style(Varborder_var)]|"e"->[border_inline_end_style(Varborder_var)]|"bs"->[border_block_start_style(Varborder_var)]|"be"->[border_block_end_style(Varborder_var)]|"t"->[border_top_style(Varborder_var)]|"r"->[border_right_style(Varborder_var)]|"b"->[border_bottom_style(Varborder_var)]|_->[border_left_style(Varborder_var)]letside_width_property=function|"x"->"border-inline-width"|"y"->"border-block-width"|"s"->"border-inline-start-width"|"e"->"border-inline-end-width"|"bs"->"border-block-start-width"|"be"->"border-block-end-width"|"t"->"border-top-width"|"r"->"border-right-width"|"b"->"border-bottom-width"|_->"border-left-width"letside_widthsidew=make_side_util(funv->side_width_propssidevw)letside_width_pxsiden=side_widthside(Px(float_of_intn))(** Border side utilities with specific widths *)letborder_solid=border_style_utilSolidletborder_dashed=border_style_utilDashedletborder_dotted=border_style_utilDottedletborder_double=border_style_utilDoubleletborder_hidden=border_style_utilHiddenletborder_none=border_style_utilNone(* Arbitrary radii go through the same normalisation as the other arbitrary
length utilities, so calc() and var() references parse. *)letparse_lengthstr:lengthoption=(* A radius and an outline offset each write one longhand, so a data-type
hint only chooses that longhand and the reader is handed what follows
it. *)Option.bind(Parse.value_after_hintstr)(funvalue->Css.parse_length(Parse.normalize_css_math_operators(Parse.decode_arbitrary_valuevalue)))(* A bare number is not a CSS length, but Tailwind admits [border-[3]] and
emits it as a width, so it keeps the px reading it has always had. *)letparse_bare_numberstr=letis_number_charc=(c>='0'&&c<='9')||c='.'||c='-'inifstr<>""&&String.for_allis_number_charstrthenfloat_of_string_optstrelseNone(* [border-[X]] is a width or a colour, and the class grammar has to say which
before the value is read. The three CSS line-width keywords are the only
idents on the width side. *)letis_line_width_keyword=function|"thin"|"medium"|"thick"->true|_->false(* Which value the width reader is handed, once the hint has said whether the
bracket is a width at all. [length:] and [line-width:] name the width side;
[color:], an unknown hint and the empty one all belong to the colour
handler, so this declines and leaves them to it. Unhinted, the bracket has
to look like a width or a colour would be read as one. *)letwidth_bracket_value~looks_like_widthinner=matchParse.data_type_hintinnerwith|Some(("length"|"line-width"),value)->Somevalue|Some_->None|None->iflooks_like_widthinnerthenSomeinnerelseNone(* A width hint says the bracket is a width whatever the value turns out to
be, so a value no width grammar reads is still a width - forwarded verbatim
under the token-stream contract. Without the hint the same text names no
utility, because nothing says which side of the family it is for. *)lethinted_token_streaminner=matchParse.data_type_hintinnerwith|Some(("length"|"line-width"|"number"|"percentage"),_)->Parse.arbitrary_declaration_valueinner|_->None(* cascade's own border-width reader answers the line-width keywords, every
unit [Css.border_width] names, [calc()] and [var()]. The units only
[Css.length] has (the dynamic-viewport and container-query families) are
not border widths there either, so such a bracket is still refused. *)letparse_border_widthinner:Css.border_widthoption=letcursor=Cascade.Cursor.of_string(Parse.normalize_css_math_operators(Parse.decode_arbitrary_valueinner))inmatchCascade.Cursor.try_parse_full_errCss.Properties.read_border_widthcursorwith|Okw->Somew|Error_->(matchparse_bare_numberinnerwith|Somef->Some(Pxf)|None->None)(* cascade types outline-width as a [border_width], the line-width grammar it
shares with the border sides, so read it as one rather than reading a
length and converting where it is written. A bare number goes through
Tailwind's generator as it was written and its minifier reads it as pixels,
which is the spelling its own test corpus records and the one [--diff]
compares. *)letparse_outline_widthinner:Css.border_widthoption=matchparse_border_widthinnerwith|Some_asw->w|None->(matchparse_bare_numberinnerwith|Somef->Some(Pxf)|None->None)(* A [--radius-*] token the project declared names a radius the built-in scale
has no slot for; they share the slot after the scale, the way the project's
font families and text sizes share theirs. *)letradius_named_cache=Domain_cache.v8letradius_named_varname=Domain_cache.or_addradius_named_cachename(fun()->Var.themeCss.Length("radius-"^name)~order:(7,11))letradius_none_var=Var.themeCss.Length"radius-none"~order:(7,0)letradius_full_var=Var.themeCss.Length"radius-full"~order:(7,1)letradius_xs_var=Var.themeCss.Length"radius-xs"~order:(7,2)letradius_sm_var=Var.themeCss.Length"radius-sm"~order:(7,3)letradius_var=Var.themeCss.Length"radius"~order:(7,4)letradius_md_var=Var.themeCss.Length"radius-md"~order:(7,5)letradius_lg_var=Var.themeCss.Length"radius-lg"~order:(7,6)letradius_xl_var=Var.themeCss.Length"radius-xl"~order:(7,7)letradius_2xl_var=Var.themeCss.Length"radius-2xl"~order:(7,8)letradius_3xl_var=Var.themeCss.Length"radius-3xl"~order:(7,9)letradius_4xl_var=Var.themeCss.Length"radius-4xl"~order:(7,10)(* Publish the radius scale through the theme-token registry, the way rule.ml
publishes the breakpoints, so [rounded-[theme(--radius-lg)]] resolves and
[theme(static)] emits the scale. [--radius-none] and [--radius-full] are
not in Tailwind's default theme - their utilities carry the value - so they
stay out of the registry. *)let()=List.iter(fun(var,value)->Theme.register_defaultvarvalue)[(radius_xs_var,(Css.Rem0.125:Css.length));(radius_sm_var,Css.Rem0.25);(radius_md_var,Css.Rem0.375);(radius_lg_var,Css.Rem0.5);(radius_xl_var,Css.Rem0.75);(radius_2xl_var,Css.Rem1.0);(radius_3xl_var,Css.Rem1.5);(radius_4xl_var,Css.Rem2.0);]letradius_valuelen=Css.Radius{horizontal=[Css.Lengthlen];vertical=None}(* Tailwind's --radius-full default is calc(infinity * 1px); FLT_MAX is the
canonical large value that infinity folds to, so the all-corners and
per-side/corner "full" utilities share it. *)letradius_full_len:Css.length=Css.Px3.40282e38(* Map a [Corner.t] to the corner/side radius declarations for a given length.
Shared by both the sized and arbitrary radius utilities; [Corner.All] uses
the [border-radius] shorthand, all others target the matching
corner/logical properties. *)(* The longhands each corner names, for a value no typed setter can hold. *)letradius_properties_for_position=function|Corner.All->["border-radius"]|Corner.Top->["border-top-left-radius";"border-top-right-radius"]|Corner.Right->["border-top-right-radius";"border-bottom-right-radius"]|Corner.Bottom->["border-bottom-right-radius";"border-bottom-left-radius"]|Corner.Left->["border-top-left-radius";"border-bottom-left-radius"]|Corner.Top_left->["border-top-left-radius"]|Corner.Top_right->["border-top-right-radius"]|Corner.Bottom_right->["border-bottom-right-radius"]|Corner.Bottom_left->["border-bottom-left-radius"]|Corner.Start->["border-start-start-radius";"border-end-start-radius"]|Corner.End->["border-start-end-radius";"border-end-end-radius"]|Corner.Start_start->["border-start-start-radius"]|Corner.Start_end->["border-start-end-radius"]|Corner.End_start->["border-end-start-radius"]|Corner.End_end->["border-end-end-radius"]letradius_decls_for_positionpos(len:Css.length):Css.declarationlist=matchposwith|Corner.All->[Css.border_radius(radius_valuelen)]|Corner.Top->[Css.border_top_left_radiuslen;Css.border_top_right_radiuslen]|Corner.Right->[Css.border_top_right_radiuslen;Css.border_bottom_right_radiuslen]|Corner.Bottom->[Css.border_bottom_right_radiuslen;Css.border_bottom_left_radiuslen;]|Corner.Left->[Css.border_top_left_radiuslen;Css.border_bottom_left_radiuslen]|Corner.Top_left->[Css.border_top_left_radiuslen]|Corner.Top_right->[Css.border_top_right_radiuslen]|Corner.Bottom_right->[Css.border_bottom_right_radiuslen]|Corner.Bottom_left->[Css.border_bottom_left_radiuslen]|Corner.Start->[Css.border_start_start_radiuslen;Css.border_end_start_radiuslen]|Corner.End->[Css.border_start_end_radiuslen;Css.border_end_end_radiuslen]|Corner.Start_start->[Css.border_start_start_radiuslen]|Corner.Start_end->[Css.border_start_end_radiuslen]|Corner.End_end->[Css.border_end_end_radiuslen]|Corner.End_start->[Css.border_end_start_radiuslen](* Per-side/corner "full"/"none" radius: reference var(--radius-X) when the
active theme defines that radius (e.g. an @theme override, as the upstream
fixtures use), otherwise inline the literal -- matching Tailwind, which
inlines calc(infinity*1px)/0 by default but keys off the token when set. *)letscheme_keyed_radius?themekeyvar~(default:Css.length)pos=matchScheme.radius(Scheme.or_defaulttheme)keywith|Someexplicit->letdecl,r=Var.bindingvarexplicitinstyle(decl::radius_decls_for_positionpos(Varr:Css.length))|None->style(radius_decls_for_positionposdefault)(* Helper: return (decls, length_val) for the bare --radius variable. When
theme_value "radius" is set (e.g. @config theme), emit the var declaration
and use var(--radius). Otherwise inline .25rem directly. *)letradius_decl_and_val?theme():Css.declarationlist*Css.length=ifScheme.theme_valuetheme"radius"<>Nonethenletdecl,r=Var.bindingradius_var(Rem0.25)in([decl],Css.Varr)else([],Css.Rem0.25)(* Sized radius (xs/sm/md/lg/xl/2xl/3xl/4xl): always bind the theme var with
its default and reference it. *)letsized_radiusvardefaultpos=letdecl,r=Var.bindingvardefaultinstyle(decl::radius_decls_for_positionpos(Varr:Css.length))(* The single parametric radius style covering every (position, size) pair. *)letrounded_style?themepossize=matchsizewith|Rsz_none->scheme_keyed_radius?theme"none"radius_none_var~default:Css.Zeropos|Rsz_full->scheme_keyed_radius?theme"full"radius_full_var~default:radius_full_lenpos|Rsz_default->letextra,v=radius_decl_and_val?theme()instyle(extra@radius_decls_for_positionposv)|Rsz_xs->sized_radiusradius_xs_var(Css.Rem0.125)pos|Rsz_sm->sized_radiusradius_sm_var(Css.Rem0.25)pos|Rsz_md->sized_radiusradius_md_var(Css.Rem0.375)pos|Rsz_lg->sized_radiusradius_lg_var(Css.Rem0.5)pos|Rsz_xl->sized_radiusradius_xl_var(Css.Rem0.75)pos|Rsz_2xl->sized_radiusradius_2xl_var(Css.Rem1.0)pos|Rsz_3xl->sized_radiusradius_3xl_var(Css.Rem1.5)pos|Rsz_4xl->sized_radiusradius_4xl_var(Css.Rem2.0)pos|Rsz_themename->(lettoken="radius-"^nameinmatchScheme.theme_valuethemetokenwith|None->style[]|Someraw->(matchCss.parse_lengthrawwith|None->style[]|Somelen->ifScheme.is_inline_token(Scheme.or_defaulttheme)tokenthenstyle(radius_decls_for_positionposlen)elseletdecl,r=Var.binding(radius_named_varname)leninstyle(decl::radius_decls_for_positionpos(Varr:Css.length))))|Rsz_arbitrary(_,len)->style(radius_decls_for_positionposlen)|Rsz_raw(_,value)->style(List.filter_map(funproperty->Parse.opaque_declarationpropertyvalue)(radius_properties_for_positionpos))(* Outline style variable - used by outline utilities that set the style *)letoutline_style_var=(* Tailwind emits @property --tw-outline-style after the ring group and
before the filters. property_order 21 places it just after
--tw-ring-offset-shadow (20) in the cross-family comparison; the earlier
value of 0 wrongly sorted it ahead of the whole ring/border block. *)Var.property_defaultCss.Outline_style~initial:(Solid:Css.outline_style)~property_order:21~family:`Border"tw-outline-style"(* Base outline utility - sets outline-style from var and width from scheme *)letoutline?theme()=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyinletwidth=float_of_int(Scheme.or_defaulttheme).default_outline_widthinstyle~property_rules:property_rule[Css.outline_style(Css.Varoref);Css.outline_width(Pxwidth)](* Outline-0: style from var + width: 0 *)letoutline_0=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule[Css.outline_style(Css.Varoref);Css.outline_widthZero](* Outline numeric width: outline-1, outline-2, outline-4, outline-8 *)letoutline_width_stylen=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule[Css.outline_style(Css.Varoref);Css.outline_width(Px(float_of_intn));](* Outline bracket width: outline-[12px], outline-[1.5] *)letoutline_width_bracket_style(width:Css.border_width)=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule[Css.outline_style(Css.Varoref);Css.outline_widthwidth](* outline-[50%]: Tailwind routes a percentage to the width by its type and
writes [outline-width: 50%], which the line-width grammar refuses and every
browser drops, leaving the [outline-style] beside it to paint a [medium]
outline. tw emits what the browser keeps. *)letoutline_width_dropped_style=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule[Css.outline_style(Css.Varoref)](* A width the grammar declines still names the width longhand, so the rule
carries the style declaration and the value the browser will drop. *)letoutline_width_raw_stylevalue=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyinstyle~property_rules:property_rule(Css.outline_style(Css.Varoref)::Option.to_list(Parse.opaque_declaration"outline-width"value))(* Outline typed bracket width: outline-[length:var(...)], etc. *)letoutline_width_var_stylev=letoref=Var.referenceoutline_style_varinletproperty_rule=matchVar.property_ruleoutline_style_varwith|Somerule->rule|None->Css.emptyin(* Strip type prefix like "length:" before extracting var name *)letvar_part=matchString.index_optv':'with|Somei->String.subv(i+1)(String.lengthv-i-1)|None->vinletbare_name=Parse.extract_var_namevar_partinletvar_ref:Css.border_widthCss.var=Var.bracketbare_nameinstyle~merge_key:"outline-"~property_rules:property_rule[Css.outline_style(Css.Varoref);Css.outline_width(Varvar_ref)](* Outline style utilities that set the variable *)letoutline_hidden=letdecl=Var.setoutline_style_varCss.Nonein(* Base style: outline-style: none *)(* In forced-colors mode, reset outline with shorthand + offset *)letforced_colors_active=Css.Media.Cond(Css.Media.Feature(Css.Media.Plain(Css.Media.Forced_colors,Css.Media.IdentCss.Media.Active)))inletmedia_rule=Css.media~condition:forced_colors_active[Css.rule~selector:(Css.Selector.class_"_")[Css.outline_offset(Px2.);Css.outline(Shorthand{width=Some(Px2.);style=SomeSolid;color=Some(Css.hex"#0000");});];]instyle~rules:(Some[media_rule])[decl;Css.outline_styleCss.None](* Outline offset accepts any bare integer, like the border widths. *)letoutline_offset_pxn=style[Css.outline_offset(Px(float_of_intn))](* Negative outline offset - use calc(Npx * -1) format *)letneg_outline_offsetn=letcalc:Css.length=Calc(Expr(Val(Px(float_of_intn)),Mul,Num(-1.)))instyle[Css.outline_offsetcalc]letoutline_offset_var_stylev=letbare_name=Parse.extract_var_namevinletvar_ref:Css.lengthCss.var=Var.bracketbare_nameinstyle[Css.outline_offset(Varvar_ref)]letneg_outline_offset_var_stylev=letbare_name=Parse.extract_var_namevinletneg_len:Css.length=Calc(Calc.mul(Calc.varbare_name)(Calc.float(-1.)))instyle[Css.outline_offsetneg_len]letto_styletheme:t->Style.t=letborder_default()=border_default~theme()inletoutline()=outline~theme()infunction(* Border width utilities *)|Border->border_default()|Border_0->border_0|Border_2->border_2|Border_4->border_4|Border_8->border_8|Border_widthn->border_nn|Border_width_bracket(_,w)->border_width_bracket_stylew|Border_side_width_bracket(side,_,w)->side_widthsidew|Border_width_raw(_,value)->make_border_util(Option.to_list(Parse.opaque_declaration"border-width"value))|Border_side_width_raw(side,_,value)->make_side_util(funv->side_style_propssidev@Option.to_list(Parse.opaque_declaration(side_width_propertyside)value))|Border_side_width(side,n)->side_width_pxsiden(* Border side/axis utilities *)|Border_t->side_width_px"t"1|Border_r->side_width_px"r"1|Border_b->side_width_px"b"1|Border_l->side_width_px"l"1|Border_x->side_width_px"x"1|Border_y->side_width_px"y"1|Border_x_widthn->side_width_px"x"n|Border_y_widthn->side_width_px"y"n|Border_s->side_width_px"s"1|Border_e->side_width_px"e"1|Border_bs->side_width_px"bs"1|Border_be->side_width_px"be"1|Border_s_widthn->side_width_px"s"n|Border_e_widthn->side_width_px"e"n|Border_bs_widthn->side_width_px"bs"n|Border_be_widthn->side_width_px"be"n(* Border style utilities *)|Border_solid->border_solid|Border_dashed->border_dashed|Border_dotted->border_dotted|Border_double->border_double|Border_hidden->border_hidden|Border_none->border_none(* Border radius utilities (parametric) *)|Rounded(pos,size)->rounded_style~themepossize(* Outline utilities *)|Outline->outline()|Outline_0->outline_0|Outline_widthn->outline_width_stylen|Outline_width_bracket(_,len)->outline_width_bracket_stylelen|Outline_width_dropped_->outline_width_dropped_style|Outline_width_raw(_,value)->outline_width_raw_stylevalue|Outline_width_varv->outline_width_var_stylev|Outline_hidden->outline_hidden|Outline_offsetn->outline_offset_pxn|Outline_offset_varv->outline_offset_var_stylev|Outline_offset_raw(_,v)->style(Option.to_list(Parse.opaque_declaration"outline-offset"v))|Outline_offset_arbitraryv->(matchparse_lengthvwith|Somel->style[Css.outline_offsetl]|None->style[Css.outline_offset(Px0.)])|Neg_outline_offsetn->neg_outline_offsetn|Neg_outline_offset_varv->neg_outline_offset_var_stylevleterr_not_utility=Error(`Msg"Not a border utility")(* Parse the side/corner segment of a class into the corners it rounds. *)letcorner_of_string=function|"s"->SomeCorner.Start|"e"->SomeCorner.End|"t"->SomeCorner.Top|"r"->SomeCorner.Right|"b"->SomeCorner.Bottom|"l"->SomeCorner.Left|"ss"->SomeCorner.Start_start|"se"->SomeCorner.Start_end|"ee"->SomeCorner.End_end|"es"->SomeCorner.End_start|"tl"->SomeCorner.Top_left|"tr"->SomeCorner.Top_right|"br"->SomeCorner.Bottom_right|"bl"->SomeCorner.Bottom_left|_->None(* Parse a rounded size token (the t-shirt segment of a class). *)letrounded_size_of_string=function|"none"->SomeRsz_none|"xs"->SomeRsz_xs|"sm"->SomeRsz_sm|"md"->SomeRsz_md|"lg"->SomeRsz_lg|"xl"->SomeRsz_xl|"2xl"->SomeRsz_2xl|"3xl"->SomeRsz_3xl|"4xl"->SomeRsz_4xl|"full"->SomeRsz_full|_->None(* A radius the project named in its [@theme]. The built-in scale is published
through the static token catalog, so a built-in name is answered by
[rounded_size_of_string] before this is consulted. *)letis_theme_radiusthemen=rounded_size_of_stringn=None&&Scheme.theme_value(Sometheme)("radius-"^n)<>None(* Forty apart, so a side's widths and its bracket never reach the next. *)(* Every border width writes a property another one writes too, so their
order decides which wins. Tailwind groups them side-major: the all-sides
width first, then each axis and logical side, then the physical sides.
Each side gets a hundred-wide band, since a width the scale does not name
still has to sort between its neighbours. *)letwidth_band=function|""->300|"x"->400|"y"->500|"s"->600|"e"->700|"bs"->800|"be"->900|"t"->1000|"r"->1100|"b"->1200|_->1300(* Within a band the bare utility leads, then the widths in numeric order,
then the arbitrary width. A width past what the band holds shares the slot
below the arbitrary one. *)letwidth_slotsiden=width_bandside+1+minn97letwidth_bracket_slotside=width_bandside+99letsuborder=function(* Border radius utilities - flat suborder per position group for natural
sort by class name *)|Rounded(pos,_)->((* Position groups sort by the CSS properties they write, matching
Tailwind: the logical corners (start/end) first, then the physical
ones grouped by their first corner clockwise -- top, then left, then
right, then bottom. Values within a group share a suborder and
tie-break by class name. *)matchposwith|Corner.All->0|Corner.Start->10|Corner.Start_start->20|Corner.End->30|Corner.Start_end->40|Corner.End_end->50|Corner.End_start->60|Corner.Top->100|Corner.Left->110|Corner.Top_left->120|Corner.Right->130|Corner.Top_right->140|Corner.Bottom->150|Corner.Bottom_right->160|Corner.Bottom_left->170)(* Border width utilities, side-major: the sides run x, y, s, e, bs, be,
then t, r, b, l, which is the order Tailwind writes them in. *)|Border->width_band""|Border_0->width_slot""0|Border_2->width_slot""2|Border_4->width_slot""4|Border_8->width_slot""8|Border_widthn->width_slot""n|Border_width_bracket_|Border_width_raw_->width_bracket_slot""|Border_x->width_band"x"|Border_x_widthn->width_slot"x"n|Border_y->width_band"y"|Border_y_widthn->width_slot"y"n|Border_s->width_band"s"|Border_s_widthn->width_slot"s"n|Border_e->width_band"e"|Border_e_widthn->width_slot"e"n|Border_bs->width_band"bs"|Border_bs_widthn->width_slot"bs"n|Border_be->width_band"be"|Border_be_widthn->width_slot"be"n|Border_side_width_bracket(side,_,_)|Border_side_width_raw(side,_,_)->width_bracket_slotside|Border_side_width(side,n)->width_slotsiden|Border_t->width_band"t"|Border_r->width_band"r"|Border_b->width_band"b"|Border_l->width_band"l"(* Border style utilities (1400-1499) - alphabetical *)|Border_dashed->1400|Border_dotted->1401|Border_double->1402|Border_hidden->1403|Border_none->1404|Border_solid->1405(* Outline utilities — hidden first, then width, then offset. The colors
(color.ml, 3000-28000) and the styles (Outline_style_handler,
30000-30004) close the family. *)|Outline_hidden->1990|Outline->1999|Outline_0->2000|Outline_widthn->2000+n|Outline_width_bracket_|Outline_width_dropped_|Outline_width_raw_->2009|Outline_width_var_->2010(* Outline offset — negatives before positives *)|Neg_outline_offsetn->2200+n|Neg_outline_offset_var_->2209|Outline_offsetn->2210+n|Outline_offset_var_->2299|Outline_offset_arbitrary_|Outline_offset_raw_->2215(* The ten sides a border width can name: the two axes, the four logical sides
and the four physical ones. *)letis_border_side=function|"t"|"r"|"b"|"l"|"x"|"y"|"s"|"e"|"bs"|"be"->true|_->falseletof_classthemeclass_name=letparts=Parse.split_classclass_nameinmatchpartswith|["border"]->OkBorder|["border";"0"]->OkBorder_0|["border";"2"]->OkBorder_2|["border";"4"]->OkBorder_4|["border";"8"]->OkBorder_8|["border";n]whenmatchParse.decimal_intnwithSomew->w>0|None->false->Ok(Border_width(int_of_stringn))|["border";"t"]->OkBorder_t|["border";"r"]->OkBorder_r|["border";"b"]->OkBorder_b|["border";"l"]->OkBorder_l|["border";"x"]->OkBorder_x|["border";"y"]->OkBorder_y|["border";"x";n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_x_width(int_of_stringn))|["border";"y";n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_y_width(int_of_stringn))|["border";"s"]->OkBorder_s|["border";"e"]->OkBorder_e|["border";"bs"]->OkBorder_bs|["border";"be"]->OkBorder_be|["border";"s";n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_s_width(int_of_stringn))|["border";"e";n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_e_width(int_of_stringn))|["border";"bs";n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_bs_width(int_of_stringn))|["border";"be";n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_be_width(int_of_stringn))|["border";(("t"|"r"|"b"|"l")asside);n]whenmatchParse.decimal_intnwithSomew->w>=0|None->false->Ok(Border_side_width(side,int_of_stringn))|["border";"solid"]->OkBorder_solid|["border";"dashed"]->OkBorder_dashed|["border";"dotted"]->OkBorder_dotted|["border";"double"]->OkBorder_double|["border";"hidden"]->OkBorder_hidden|["border";"none"]->OkBorder_none|["border";v]whenParse.is_bracket_valuev->(letinner=Parse.bracket_innervinletis_numeric_startc=(c>='0'&&c<='9')||c='.'||c='-'inletlooks_like_widths=(String.lengths>0&&is_numeric_starts.[0])||Parse.starts_with_math_functions||is_line_width_keywordsinmatchwidth_bracket_value~looks_like_widthinnerwith|None->err_not_utility|Somevalue->(matchparse_border_widthvaluewith|Somew->Ok(Border_width_bracket(inner,w))|None->(matchhinted_token_streaminnerwith|Someraw->Ok(Border_width_raw(inner,raw))|None->err_not_utility)))|["border";side;v]whenis_border_sideside&&Parse.is_bracket_valuev->(letinner=Parse.bracket_innervinletis_numeric_startc=(c>='0'&&c<='9')||c='.'inletlooks_like_widths=(String.lengths>0&&is_numeric_starts.[0])||Parse.starts_with_math_functions||is_line_width_keywordsinmatchwidth_bracket_value~looks_like_widthinnerwith|None->err_not_utility|Somevalue->(matchparse_border_widthvaluewith|Somew->Ok(Border_side_width_bracket(side,inner,w))|None->(matchhinted_token_streaminnerwith|Someraw->Ok(Border_side_width_raw(side,inner,raw))|None->err_not_utility)))(* Border radius utilities (parametric). [rounded] / [rounded-<size>] target
all corners; [rounded-<pos>] / [rounded-<pos>-<size>] target a side or
corner. Sizes and positions are disjoint token sets. *)(* The bare [rounded] and [rounded-<pos>] inline the deprecated [--radius]
token, so a [@theme] block that removed it leaves them no utility. *)|["rounded"]whenScheme.is_removedtheme"radius"->err_not_utility|["rounded";pos]whenOption.is_some(corner_of_stringpos)&&Scheme.is_removedtheme"radius"->err_not_utility|["rounded"]->Ok(Rounded(Corner.All,Rsz_default))|["rounded";v]whenParse.is_bracket_valuev->(letinner=Parse.bracket_innervinmatchparse_lengthinnerwith|Somelen->Ok(Rounded(Corner.All,Rsz_arbitrary(inner,len)))|None->(matchParse.arbitrary_declaration_valueinnerwith|Someraw->Ok(Rounded(Corner.All,Rsz_raw(inner,raw)))|None->err_not_utility))|["rounded";tok]->(matchrounded_size_of_stringtokwith|Somesize->Ok(Rounded(Corner.All,size))|None->(matchcorner_of_stringtokwith|Somepos->Ok(Rounded(pos,Rsz_default))|None->ifis_theme_radiusthemetokthenOk(Rounded(Corner.All,Rsz_themetok))elseerr_not_utility))|["rounded";pos;v]whenParse.is_bracket_valuev->(letinner=Parse.bracket_innervinmatch(corner_of_stringpos,parse_lengthinner)with|Somepos,Somelen->Ok(Rounded(pos,Rsz_arbitrary(inner,len)))|Somepos,None->(matchParse.arbitrary_declaration_valueinnerwith|Someraw->Ok(Rounded(pos,Rsz_raw(inner,raw)))|None->err_not_utility)|None,_->err_not_utility)|["rounded";pos;size]->(match(corner_of_stringpos,rounded_size_of_stringsize)with|Somepos,Somesize->Ok(Rounded(pos,size))|Somepos,Nonewhenis_theme_radiusthemesize->Ok(Rounded(pos,Rsz_themesize))|_->err_not_utility)|["outline"]->OkOutline|["outline";"0"]->OkOutline_0|["outline";n]whenmatchParse.decimal_intnwithSomew->w>0|None->false->Ok(Outline_width(int_of_stringn))|["outline";v]whenParse.is_bracket_valuev->(letinner=Parse.bracket_innervinletstartsprefixs=String.starts_with~prefixsinlethinted_width=matchParse.data_type_hintinnerwith|Some(("length"|"number"|"percentage"),value)->Somevalue|_->Nonein(* A data-type hint says how to read the value written after it; only a
var() reference there names a custom property. *)matchhinted_widthwith|SomevaluewhenParse.is_varvalue->Ok(Outline_width_varinner)|Somevalue->(matchparse_outline_widthvaluewith|Somelen->Ok(Outline_width_bracket(inner,len))|None->((* [percentage:10%] reads as a width [outline-width] cannot
take, the same value [outline-[50%]] infers. *)matchparse_lengthvaluewith|Some(Pct_)->Ok(Outline_width_droppedinner)|_->(matchhinted_token_streaminnerwith|Someraw->Ok(Outline_width_raw(inner,raw))|None->err_not_utility)))|None->ifstarts"var("innerthen(* Bare var() defaults to color for outline, not width *)err_not_utilityelseifstarts"color:"innerthenerr_not_utilityelseifstarts"#"innerthenerr_not_utilityelse(* Only accept if it looks like a number/length/percentage, not a
named color like "black" *)letis_numeric_startc=(c>='0'&&c<='9')||c='.'||c='-'inif(String.lengthinner>0&&is_numeric_startinner.[0])||Parse.starts_with_math_functioninnerthenmatchparse_outline_widthinnerwith|Somelen->Ok(Outline_width_bracket(inner,len))|None->(matchparse_lengthinnerwith|Some(Pct_)->Ok(Outline_width_droppedinner)|_->err_not_utility)elseerr_not_utility)(* outline-none/solid/dashed/dotted/double handled by
Outline_style_handler *)|["outline";"hidden"]->OkOutline_hidden|["outline";"offset";v]whenParse.is_bracket_valuev->(letinner=Parse.bracket_innervinifParse.is_varinnerthenOk(Outline_offset_varinner)elseifparse_lengthinner<>NonethenOk(Outline_offset_arbitraryinner)elsematchParse.arbitrary_declaration_valueinnerwith|Someraw->Ok(Outline_offset_raw(inner,raw))|None->err_not_utility)|["outline";"offset";n]->(matchParse.decimal_intnwith|Someiwheni>=0->Ok(Outline_offseti)|_->err_not_utility)(* Negative outline offset: -outline-offset-N starts with empty string *)|""::"outline"::"offset"::restwhenrest<>[]->(letvalue=String.concat"-"restinifParse.is_bracket_valuevaluethenletinner=Parse.bracket_innervalueinifParse.is_varinnerthenOk(Neg_outline_offset_varinner)elseerr_not_utilityelsematchParse.decimal_intvaluewith|Someiwheni>0->Ok(Neg_outline_offseti)|_->err_not_utility)(* ring* handled in Effects *)|_->err_not_utilityletto_class=function|Border->"border"|Border_0->"border-0"|Border_2->"border-2"|Border_4->"border-4"|Border_8->"border-8"|Border_widthn->"border-"^string_of_intn|Border_width_bracket(v,_)|Border_width_raw(v,_)->"border-["^v^"]"|Border_side_width_bracket(side,inner,_)|Border_side_width_raw(side,inner,_)->"border-"^side^"-["^inner^"]"|Border_side_width(side,n)->"border-"^side^"-"^string_of_intn|Border_t->"border-t"|Border_r->"border-r"|Border_b->"border-b"|Border_l->"border-l"|Border_x->"border-x"|Border_y->"border-y"|Border_x_widthn->"border-x-"^string_of_intn|Border_y_widthn->"border-y-"^string_of_intn|Border_s->"border-s"|Border_e->"border-e"|Border_bs->"border-bs"|Border_be->"border-be"|Border_s_widthn->"border-s-"^string_of_intn|Border_e_widthn->"border-e-"^string_of_intn|Border_bs_widthn->"border-bs-"^string_of_intn|Border_be_widthn->"border-be-"^string_of_intn|Border_solid->"border-solid"|Border_dashed->"border-dashed"|Border_dotted->"border-dotted"|Border_double->"border-double"|Border_hidden->"border-hidden"|Border_none->"border-none"|Rounded(pos,size)->letpos_str=matchposwith|Corner.All->""|Corner.Start->"-s"|Corner.End->"-e"|Corner.Top->"-t"|Corner.Right->"-r"|Corner.Bottom->"-b"|Corner.Left->"-l"|Corner.Start_start->"-ss"|Corner.Start_end->"-se"|Corner.End_end->"-ee"|Corner.End_start->"-es"|Corner.Top_left->"-tl"|Corner.Top_right->"-tr"|Corner.Bottom_right->"-br"|Corner.Bottom_left->"-bl"inletsize_str=matchsizewith|Rsz_default->""|Rsz_none->"-none"|Rsz_xs->"-xs"|Rsz_sm->"-sm"|Rsz_md->"-md"|Rsz_lg->"-lg"|Rsz_xl->"-xl"|Rsz_2xl->"-2xl"|Rsz_3xl->"-3xl"|Rsz_4xl->"-4xl"|Rsz_full->"-full"|Rsz_themename->"-"^name|Rsz_arbitrary(raw,_)|Rsz_raw(raw,_)->"-["^raw^"]"in"rounded"^pos_str^size_str|Outline->"outline"|Outline_0->"outline-0"|Outline_widthn->"outline-"^string_of_intn|Outline_width_bracket(v,_)|Outline_width_raw(v,_)|Outline_width_droppedv|Outline_width_varv->"outline-["^v^"]"|Outline_hidden->"outline-hidden"|Outline_offsetn->"outline-offset-"^string_of_intn|Outline_offset_varv->"outline-offset-["^v^"]"|Outline_offset_arbitraryv|Outline_offset_raw(v,_)->"outline-offset-["^v^"]"|Neg_outline_offsetn->"-outline-offset-"^string_of_intn|Neg_outline_offset_varv->"-outline-offset-["^v^"]"letexamples=[Border_0;Border_x;Border_y;Border_solid;Outline_width2;Outline_offset2;Rounded(Corner.All,Rsz_sm);]endopenHandlermoduleUtility_factory=Utility.Make(Handler)letutility=Utility_factory.v(** Separate handler for outline style utilities that need to come after outline
colors (priority 23) AND after ring/shadow effects (priority 25). These are:
outline-dashed, outline-dotted, outline-double, outline-none, outline-solid.
*)moduleOutline_style_handler=structopenStyletypet=Dashed|Dotted|Double|None_|Solidletname="outline_style"letpriority_=37letto_style_theme=function|Dashed->letdecl=Var.setHandler.outline_style_varCss.Dashedinstyle[decl;Css.outline_styleCss.Dashed]|Dotted->letdecl=Var.setHandler.outline_style_varCss.Dottedinstyle[decl;Css.outline_styleCss.Dotted]|Double->letdecl=Var.setHandler.outline_style_varCss.Doubleinstyle[decl;Css.outline_styleCss.Double]|None_->letdecl=Var.setHandler.outline_style_varCss.Noneinstyle[decl;Css.outline_styleCss.None]|Solid->letdecl=Var.setHandler.outline_style_varCss.Solidinstyle[decl;Css.outline_styleCss.Solid](* These outline-style utilities form a late property band. *)letsuborder=function|Dashed->30000|Dotted->30001|Double->30002|None_->30003|Solid->30004leterr_not_utility=Error(`Msg"Not an outline style utility")letof_class_themeclass_name=letparts=Parse.split_classclass_nameinmatchpartswith|["outline";"dashed"]->OkDashed|["outline";"dotted"]->OkDotted|["outline";"double"]->OkDouble|["outline";"none"]->OkNone_|["outline";"solid"]->OkSolid|_->err_not_utilityletto_class=function|Dashed->"outline-dashed"|Dotted->"outline-dotted"|Double->"outline-double"|None_->"outline-none"|Solid->"outline-solid"letexamples=[Solid]endmoduleOutline_style_utility=Utility.Make(Outline_style_handler)letoutline_style_utility=Outline_style_utility.v(** {1 Border Width Utilities} *)letborder=utilityBorderletborder_0=utilityBorder_0letborder_2=utilityBorder_2letborder_4=utilityBorder_4letborder_8=utilityBorder_8letborder_t=utilityBorder_tletborder_r=utilityBorder_rletborder_b=utilityBorder_bletborder_l=utilityBorder_lletborder_x=utilityBorder_xletborder_y=utilityBorder_y(** {1 Border Style Utilities} *)letborder_solid=utilityBorder_solidletborder_dashed=utilityBorder_dashedletborder_dotted=utilityBorder_dottedletborder_double=utilityBorder_doubleletborder_hidden=utilityBorder_hiddenletborder_none=utilityBorder_none(** {1 Border Color Utilities} *)(* Border width utilities with semantic names matching tw.mli *)letborder_xs=border(* 1px *)letborder_sm=border_2(* 2px *)letborder_md=border_4(* 4px *)letborder_lg=border_4(* 4px *)letborder_xl=border_8(* 8px *)letborder_2xl=border_8(* 8px *)letborder_3xl=border_8(* 8px *)letborder_full=border_8(* 8px *)(** {1 Border Radius Utilities} *)letrounded=utility(Rounded(Corner.All,Rsz_default))letrounded_none=utility(Rounded(Corner.All,Rsz_none))letrounded_xs=utility(Rounded(Corner.All,Rsz_xs))letrounded_sm=utility(Rounded(Corner.All,Rsz_sm))letrounded_md=utility(Rounded(Corner.All,Rsz_md))letrounded_lg=utility(Rounded(Corner.All,Rsz_lg))letrounded_xl=utility(Rounded(Corner.All,Rsz_xl))letrounded_2xl=utility(Rounded(Corner.All,Rsz_2xl))letrounded_3xl=utility(Rounded(Corner.All,Rsz_3xl))letrounded_4xl=utility(Rounded(Corner.All,Rsz_4xl))letrounded_full=utility(Rounded(Corner.All,Rsz_full))(** {2 Side-specific rounded utilities - top} *)letrounded_t=utility(Rounded(Corner.Top,Rsz_default))letrounded_t_none=utility(Rounded(Corner.Top,Rsz_none))letrounded_t_xs=utility(Rounded(Corner.Top,Rsz_xs))letrounded_t_sm=utility(Rounded(Corner.Top,Rsz_sm))letrounded_t_md=utility(Rounded(Corner.Top,Rsz_md))letrounded_t_lg=utility(Rounded(Corner.Top,Rsz_lg))letrounded_t_xl=utility(Rounded(Corner.Top,Rsz_xl))letrounded_t_2xl=utility(Rounded(Corner.Top,Rsz_2xl))letrounded_t_3xl=utility(Rounded(Corner.Top,Rsz_3xl))letrounded_t_4xl=utility(Rounded(Corner.Top,Rsz_4xl))letrounded_t_full=utility(Rounded(Corner.Top,Rsz_full))(** {2 Side-specific rounded utilities - right} *)letrounded_r=utility(Rounded(Corner.Right,Rsz_default))letrounded_r_none=utility(Rounded(Corner.Right,Rsz_none))letrounded_r_xs=utility(Rounded(Corner.Right,Rsz_xs))letrounded_r_sm=utility(Rounded(Corner.Right,Rsz_sm))letrounded_r_md=utility(Rounded(Corner.Right,Rsz_md))letrounded_r_lg=utility(Rounded(Corner.Right,Rsz_lg))letrounded_r_xl=utility(Rounded(Corner.Right,Rsz_xl))letrounded_r_2xl=utility(Rounded(Corner.Right,Rsz_2xl))letrounded_r_3xl=utility(Rounded(Corner.Right,Rsz_3xl))letrounded_r_4xl=utility(Rounded(Corner.Right,Rsz_4xl))letrounded_r_full=utility(Rounded(Corner.Right,Rsz_full))(** {2 Side-specific rounded utilities - bottom} *)letrounded_b=utility(Rounded(Corner.Bottom,Rsz_default))letrounded_b_none=utility(Rounded(Corner.Bottom,Rsz_none))letrounded_b_xs=utility(Rounded(Corner.Bottom,Rsz_xs))letrounded_b_sm=utility(Rounded(Corner.Bottom,Rsz_sm))letrounded_b_md=utility(Rounded(Corner.Bottom,Rsz_md))letrounded_b_lg=utility(Rounded(Corner.Bottom,Rsz_lg))letrounded_b_xl=utility(Rounded(Corner.Bottom,Rsz_xl))letrounded_b_2xl=utility(Rounded(Corner.Bottom,Rsz_2xl))letrounded_b_3xl=utility(Rounded(Corner.Bottom,Rsz_3xl))letrounded_b_4xl=utility(Rounded(Corner.Bottom,Rsz_4xl))letrounded_b_full=utility(Rounded(Corner.Bottom,Rsz_full))(** {2 Side-specific rounded utilities - left} *)letrounded_l=utility(Rounded(Corner.Left,Rsz_default))letrounded_l_none=utility(Rounded(Corner.Left,Rsz_none))letrounded_l_xs=utility(Rounded(Corner.Left,Rsz_xs))letrounded_l_sm=utility(Rounded(Corner.Left,Rsz_sm))letrounded_l_md=utility(Rounded(Corner.Left,Rsz_md))letrounded_l_lg=utility(Rounded(Corner.Left,Rsz_lg))letrounded_l_xl=utility(Rounded(Corner.Left,Rsz_xl))letrounded_l_2xl=utility(Rounded(Corner.Left,Rsz_2xl))letrounded_l_3xl=utility(Rounded(Corner.Left,Rsz_3xl))letrounded_l_4xl=utility(Rounded(Corner.Left,Rsz_4xl))letrounded_l_full=utility(Rounded(Corner.Left,Rsz_full))(** {2 Corner-specific rounded utilities - top-left} *)letrounded_tl=utility(Rounded(Corner.Top_left,Rsz_default))letrounded_tl_none=utility(Rounded(Corner.Top_left,Rsz_none))letrounded_tl_xs=utility(Rounded(Corner.Top_left,Rsz_xs))letrounded_tl_sm=utility(Rounded(Corner.Top_left,Rsz_sm))letrounded_tl_md=utility(Rounded(Corner.Top_left,Rsz_md))letrounded_tl_lg=utility(Rounded(Corner.Top_left,Rsz_lg))letrounded_tl_xl=utility(Rounded(Corner.Top_left,Rsz_xl))letrounded_tl_2xl=utility(Rounded(Corner.Top_left,Rsz_2xl))letrounded_tl_3xl=utility(Rounded(Corner.Top_left,Rsz_3xl))letrounded_tl_4xl=utility(Rounded(Corner.Top_left,Rsz_4xl))letrounded_tl_full=utility(Rounded(Corner.Top_left,Rsz_full))(** {2 Corner-specific rounded utilities - top-right} *)letrounded_tr=utility(Rounded(Corner.Top_right,Rsz_default))letrounded_tr_none=utility(Rounded(Corner.Top_right,Rsz_none))letrounded_tr_xs=utility(Rounded(Corner.Top_right,Rsz_xs))letrounded_tr_sm=utility(Rounded(Corner.Top_right,Rsz_sm))letrounded_tr_md=utility(Rounded(Corner.Top_right,Rsz_md))letrounded_tr_lg=utility(Rounded(Corner.Top_right,Rsz_lg))letrounded_tr_xl=utility(Rounded(Corner.Top_right,Rsz_xl))letrounded_tr_2xl=utility(Rounded(Corner.Top_right,Rsz_2xl))letrounded_tr_3xl=utility(Rounded(Corner.Top_right,Rsz_3xl))letrounded_tr_4xl=utility(Rounded(Corner.Top_right,Rsz_4xl))letrounded_tr_full=utility(Rounded(Corner.Top_right,Rsz_full))(** {2 Corner-specific rounded utilities - bottom-right} *)letrounded_br=utility(Rounded(Corner.Bottom_right,Rsz_default))letrounded_br_none=utility(Rounded(Corner.Bottom_right,Rsz_none))letrounded_br_xs=utility(Rounded(Corner.Bottom_right,Rsz_xs))letrounded_br_sm=utility(Rounded(Corner.Bottom_right,Rsz_sm))letrounded_br_md=utility(Rounded(Corner.Bottom_right,Rsz_md))letrounded_br_lg=utility(Rounded(Corner.Bottom_right,Rsz_lg))letrounded_br_xl=utility(Rounded(Corner.Bottom_right,Rsz_xl))letrounded_br_2xl=utility(Rounded(Corner.Bottom_right,Rsz_2xl))letrounded_br_3xl=utility(Rounded(Corner.Bottom_right,Rsz_3xl))letrounded_br_4xl=utility(Rounded(Corner.Bottom_right,Rsz_4xl))letrounded_br_full=utility(Rounded(Corner.Bottom_right,Rsz_full))(** {2 Corner-specific rounded utilities - bottom-left} *)letrounded_bl=utility(Rounded(Corner.Bottom_left,Rsz_default))letrounded_bl_none=utility(Rounded(Corner.Bottom_left,Rsz_none))letrounded_bl_xs=utility(Rounded(Corner.Bottom_left,Rsz_xs))letrounded_bl_sm=utility(Rounded(Corner.Bottom_left,Rsz_sm))letrounded_bl_md=utility(Rounded(Corner.Bottom_left,Rsz_md))letrounded_bl_lg=utility(Rounded(Corner.Bottom_left,Rsz_lg))letrounded_bl_xl=utility(Rounded(Corner.Bottom_left,Rsz_xl))letrounded_bl_2xl=utility(Rounded(Corner.Bottom_left,Rsz_2xl))letrounded_bl_3xl=utility(Rounded(Corner.Bottom_left,Rsz_3xl))letrounded_bl_4xl=utility(Rounded(Corner.Bottom_left,Rsz_4xl))letrounded_bl_full=utility(Rounded(Corner.Bottom_left,Rsz_full))(** {2 Logical property rounded utilities - start} *)letrounded_s=utility(Rounded(Corner.Start,Rsz_default))letrounded_s_none=utility(Rounded(Corner.Start,Rsz_none))letrounded_s_xs=utility(Rounded(Corner.Start,Rsz_xs))letrounded_s_sm=utility(Rounded(Corner.Start,Rsz_sm))letrounded_s_md=utility(Rounded(Corner.Start,Rsz_md))letrounded_s_lg=utility(Rounded(Corner.Start,Rsz_lg))letrounded_s_xl=utility(Rounded(Corner.Start,Rsz_xl))letrounded_s_2xl=utility(Rounded(Corner.Start,Rsz_2xl))letrounded_s_3xl=utility(Rounded(Corner.Start,Rsz_3xl))letrounded_s_4xl=utility(Rounded(Corner.Start,Rsz_4xl))letrounded_s_full=utility(Rounded(Corner.Start,Rsz_full))(** {2 Logical property rounded utilities - end} *)letrounded_e=utility(Rounded(Corner.End,Rsz_default))letrounded_e_none=utility(Rounded(Corner.End,Rsz_none))letrounded_e_xs=utility(Rounded(Corner.End,Rsz_xs))letrounded_e_sm=utility(Rounded(Corner.End,Rsz_sm))letrounded_e_md=utility(Rounded(Corner.End,Rsz_md))letrounded_e_lg=utility(Rounded(Corner.End,Rsz_lg))letrounded_e_xl=utility(Rounded(Corner.End,Rsz_xl))letrounded_e_2xl=utility(Rounded(Corner.End,Rsz_2xl))letrounded_e_3xl=utility(Rounded(Corner.End,Rsz_3xl))letrounded_e_4xl=utility(Rounded(Corner.End,Rsz_4xl))letrounded_e_full=utility(Rounded(Corner.End,Rsz_full))(** {2 Logical corner rounded utilities - start-start} *)letrounded_ss=utility(Rounded(Corner.Start_start,Rsz_default))letrounded_ss_none=utility(Rounded(Corner.Start_start,Rsz_none))letrounded_ss_xs=utility(Rounded(Corner.Start_start,Rsz_xs))letrounded_ss_sm=utility(Rounded(Corner.Start_start,Rsz_sm))letrounded_ss_md=utility(Rounded(Corner.Start_start,Rsz_md))letrounded_ss_lg=utility(Rounded(Corner.Start_start,Rsz_lg))letrounded_ss_xl=utility(Rounded(Corner.Start_start,Rsz_xl))letrounded_ss_2xl=utility(Rounded(Corner.Start_start,Rsz_2xl))letrounded_ss_3xl=utility(Rounded(Corner.Start_start,Rsz_3xl))letrounded_ss_4xl=utility(Rounded(Corner.Start_start,Rsz_4xl))letrounded_ss_full=utility(Rounded(Corner.Start_start,Rsz_full))(** {2 Logical corner rounded utilities - start-end} *)letrounded_se=utility(Rounded(Corner.Start_end,Rsz_default))letrounded_se_none=utility(Rounded(Corner.Start_end,Rsz_none))letrounded_se_xs=utility(Rounded(Corner.Start_end,Rsz_xs))letrounded_se_sm=utility(Rounded(Corner.Start_end,Rsz_sm))letrounded_se_md=utility(Rounded(Corner.Start_end,Rsz_md))letrounded_se_lg=utility(Rounded(Corner.Start_end,Rsz_lg))letrounded_se_xl=utility(Rounded(Corner.Start_end,Rsz_xl))letrounded_se_2xl=utility(Rounded(Corner.Start_end,Rsz_2xl))letrounded_se_3xl=utility(Rounded(Corner.Start_end,Rsz_3xl))letrounded_se_4xl=utility(Rounded(Corner.Start_end,Rsz_4xl))letrounded_se_full=utility(Rounded(Corner.Start_end,Rsz_full))(** {2 Logical corner rounded utilities - end-end} *)letrounded_ee=utility(Rounded(Corner.End_end,Rsz_default))letrounded_ee_none=utility(Rounded(Corner.End_end,Rsz_none))letrounded_ee_xs=utility(Rounded(Corner.End_end,Rsz_xs))letrounded_ee_sm=utility(Rounded(Corner.End_end,Rsz_sm))letrounded_ee_md=utility(Rounded(Corner.End_end,Rsz_md))letrounded_ee_lg=utility(Rounded(Corner.End_end,Rsz_lg))letrounded_ee_xl=utility(Rounded(Corner.End_end,Rsz_xl))letrounded_ee_2xl=utility(Rounded(Corner.End_end,Rsz_2xl))letrounded_ee_3xl=utility(Rounded(Corner.End_end,Rsz_3xl))letrounded_ee_4xl=utility(Rounded(Corner.End_end,Rsz_4xl))letrounded_ee_full=utility(Rounded(Corner.End_end,Rsz_full))(** {2 Logical corner rounded utilities - end-start} *)letrounded_es=utility(Rounded(Corner.End_start,Rsz_default))letrounded_es_none=utility(Rounded(Corner.End_start,Rsz_none))letrounded_es_xs=utility(Rounded(Corner.End_start,Rsz_xs))letrounded_es_sm=utility(Rounded(Corner.End_start,Rsz_sm))letrounded_es_md=utility(Rounded(Corner.End_start,Rsz_md))letrounded_es_lg=utility(Rounded(Corner.End_start,Rsz_lg))letrounded_es_xl=utility(Rounded(Corner.End_start,Rsz_xl))letrounded_es_2xl=utility(Rounded(Corner.End_start,Rsz_2xl))letrounded_es_3xl=utility(Rounded(Corner.End_start,Rsz_3xl))letrounded_es_4xl=utility(Rounded(Corner.End_start,Rsz_4xl))letrounded_es_full=utility(Rounded(Corner.End_start,Rsz_full))(** {1 Outline Utilities} *)letoutline=utilityOutlineletoutline_widthn=ifn<0theninvalid_arg"outline_width: width must be non-negative"elseifn=0thenutilityOutline_0elseutility(Outline_widthn)letoutline_none=outline_style_utilityOutline_style_handler.None_letoutline_offset_0=utility(Outline_offset0)letoutline_offset_1=utility(Outline_offset1)letoutline_offset_2=utility(Outline_offset2)letoutline_offset_4=utility(Outline_offset4)letoutline_offset_8=utility(Outline_offset8)letborder_style_var=Handler.border_style_varletparse_border_width=Handler.parse_border_width