<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like ipv6-docker-routing, modern-css-is-fun but not debugging-beyond-the-debugger, migrating-from-github-to-forgejo, sense-api, why-you-should-be-using-https</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/ipv6-docker-routing,modern-css-is-fun/unlike/debugging-beyond-the-debugger,migrating-from-github-to-forgejo,sense-api,why-you-should-be-using-https/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2026-04-01T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>Monthly Meanderings: March 2026</title>
        <link href="https://chameth.com/monthly-meanderings-2026-03/"/>
        <updated>2026-04-01T00:00:00Z</updated>
        <id>https://chameth.com/monthly-meanderings-2026-03/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Since &lt;a href=&#34;https://chameth.com/monthly-meanderings-2026-02/&#34;&gt;last month’s update&lt;/a&gt; I’ve been unpleasantly reminded that I’m middle aged, through the medium of a dodgy knee. There’s nothing quite like not being able to stand up without groaning to underscore that you’re not young any more. The ongoing game of “will this seemingly mundane activity make my knee go funny again?” is a &lt;em&gt;delight&lt;/em&gt; to play, too. I’m great at it.&lt;/p&gt;
&lt;h3 id=&#34;website-updates&#34;&gt;Website updates&lt;/h3&gt;
&lt;p&gt;Two new blog posts this month: &lt;a href=&#34;https://chameth.com/the-longest-way-to-represent-a-date/&#34;&gt;the longest way to represent a date&lt;/a&gt; is a short thought experiment on absurd date formats, and &lt;a href=&#34;https://chameth.com/modern-css-is-fun/&#34;&gt;modern CSS is fun&lt;/a&gt; goes through some neat new CSS features I’ve used recently for this site.&lt;/p&gt;
&lt;p&gt;I did some design tweaks this month: headers now have a blue background behind them&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, and a lot of components have been redesigned to have a consistent style. You can see that component in action in the new “now playing” widget I’ve added:&lt;/p&gt;
&lt;div class=&#34;now-playing raised-box&#34; data-title=&#34;Now playing&#34;&gt;
    &lt;img src=&#34;https://chameth.com/music/albums/207/cover.jpg&#34; alt=&#34;Fixed at Zero&#34; loading=&#34;lazy&#34;/&gt;
    &lt;div class=&#34;now-playing-info&#34;&gt;
        &lt;span class=&#34;artist-track&#34;&gt;VersaEmerge — Redesign Me&lt;/span&gt;
        &lt;span class=&#34;album-name&#34;&gt;Fixed at Zero&lt;/span&gt;
        &lt;span class=&#34;play-status&#34;&gt;Scrobbled 2h 6m ago&lt;/span&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Instead of each component defining its own styles (which were &lt;em&gt;mostly&lt;/em&gt; copied and pasted), there’s now a single class that handles the drop shadow, border, background colour, and the optional title. It also applies a consistent format to elements that are clickable: they use the blue accent colour for their borders, and have a glow effect shown on hover.&lt;/p&gt;
&lt;p&gt;The now playing widget is part of a larger bit of work I did on importing some music stats. I’m pulling in the data from my &lt;a href=&#34;https://www.navidrome.org/&#34;&gt;Navidrome&lt;/a&gt; instance. A new &lt;a href=&#34;https://chameth.com/music/&#34;&gt;music page&lt;/a&gt; shows my most listened albums and artists. Navidrome doesn’t store a complete play history, just the last play and the count, so I can’t do “what I listened to last month” stats until next month.&lt;/p&gt;
&lt;h3 id=&#34;other-projects&#34;&gt;Other projects&lt;/h3&gt;
&lt;p&gt;Other than a minor bug-fix update to &lt;a href=&#34;https://github.com/csmith/contempt&#34;&gt;contempt&lt;/a&gt;, my Dockerfile templating/updating tool, I’ve not done much on my other open source projects. I’ve got a bit more work to do finish migrating all my repositories from GitHub to my private &lt;a href=&#34;https://forgejo.org/&#34;&gt;Forgejo&lt;/a&gt; instance. I’ve also been thinking about mirroring my public repositories to &lt;a href=&#34;https://codeberg.org/&#34;&gt;Codeberg&lt;/a&gt; so there’s a non-GitHub way to access them.&lt;/p&gt;
&lt;h3 id=&#34;entertainment&#34;&gt;Entertainment&lt;/h3&gt;
&lt;p&gt;I apparently only watched a single film in March:&lt;/p&gt;
&lt;div class=&#34;film-review-parent&#34;&gt;
  &lt;section class=&#34;film-review raised-box&#34;&gt;
    &lt;img src=&#34;https://chameth.com/films/253/poster.jpg&#34; alt=&#34;Poster for The Substance&#34; loading=&#34;lazy&#34;/&gt;
    &lt;header&gt;
      &lt;h3 class=&#34;plain-header&#34;&gt;&lt;a href=&#34;https://chameth.com/films/the-substance-2024/&#34;&gt;The Substance&lt;/a&gt;&lt;/h3&gt;
      &lt;div&gt;&lt;/div&gt;
      &lt;div title=&#34;5/10&#34;&gt;
&lt;span class=&#34;star-rating&#34;&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-2&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-half.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Half star&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-empty.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Empty star&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-empty.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Empty star&#34;/&gt;&lt;/span&gt;
&lt;/div&gt;
      &lt;time&gt;2026-03-18&lt;/time&gt;
    &lt;/header&gt;
    &lt;div&gt;&lt;p&gt;I really didn’t get on with this. It’s too long for what it is, and over-the-top in a way that just didn’t work for me.&lt;/p&gt;
&lt;p&gt;Demi Moore and Margaret Qualley were great, but nothing else really was. The cinematography and sound design were too affected, the plot was pretty shallow and obvious, most of the body horror fell into the uncanny CGI valley for me.&lt;/p&gt;
&lt;p&gt;It’s not completely without merit: there were around 40 minutes in the middle where I was really into it, but that’s not really enough given it’s closing in on a 2.5 hour runtime.&lt;/p&gt;
&lt;p&gt;There’s something to be said for the message it’s presenting about women in Hollywood, too, but it was very heavy handed. Dennis Quaid’s character is even called Harvey; it’s not so much a subtle nod as a sledgehammer to the face.&lt;/p&gt;
&lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;Instead of films, I’ve been watching a bunch of TV. After devouring &lt;a href=&#34;https://www.themoviedb.org/tv/250307-the-pitt&#34;&gt;The Pitt&lt;/a&gt; last month, I struggled to find something to fill the hole it left. I settled on catching up on &lt;a href=&#34;https://www.themoviedb.org/tv/44006-chicago-fire&#34;&gt;Chicago Fire&lt;/a&gt; and &lt;a href=&#34;https://www.themoviedb.org/tv/58841-chicago-p-d&#34;&gt;Chicago P.D.&lt;/a&gt;. They’re both mostly about getting things done without personal drama becoming the primary focus. They’re not quite as grounded as The Pitt, but at least they’ve not completely gone off the deep end like &lt;a href=&#34;https://www.themoviedb.org/tv/75219-9-1-1&#34;&gt;9-1-1&lt;/a&gt; where the first responders end up in space somehow?&lt;/p&gt;
&lt;p&gt;I’ve also watched the first two episodes of &lt;a href=&#34;https://www.themoviedb.org/tv/288670-saturday-night-live-uk&#34;&gt;SNL UK&lt;/a&gt;. I didn’t have very high expectations, and it gave me a pleasant surprise. Both episodes so far have some hilarious sketches, and are obviously written by British comics with the typical darker, more sardonic humour that separates us from the USA.&lt;/p&gt;
&lt;p&gt;Last but not least, board games! I spent a weekend at a tabletop/LAN event with friends, so got to physically play some games for a change. I also kept up with some turn-based games on &lt;a href=&#34;https://boardgamearena.com/&#34;&gt;Board Game Arena&lt;/a&gt;, as usual.&lt;/p&gt;
&lt;ul class=&#34;played-boardgames&#34;&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Just One (2018)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/254640/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/254640/image.jpg&#34; alt=&#34;Box art of Just One&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;6 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;7 Wonders Dice (2025)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/446231/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/446231/image.jpg&#34; alt=&#34;Box art of 7 Wonders Dice&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;4 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Can&amp;#39;t Stop (1980)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/41/image.png&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/41/image.png&#34; alt=&#34;Box art of Can&amp;#39;t Stop&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;4 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Martian Dice (2011)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/99875/image.png&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/99875/image.png&#34; alt=&#34;Box art of Martian Dice&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;4 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Cartographers (2019)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/263918/image.png&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/263918/image.png&#34; alt=&#34;Box art of Cartographers&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;3 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Coffee Rush (2023)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/377061/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/377061/image.jpg&#34; alt=&#34;Box art of Coffee Rush&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;3 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Super Mega Lucky Box (2021)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/341530/image.png&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/341530/image.png&#34; alt=&#34;Box art of Super Mega Lucky Box&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;3 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Cthulhu Fluxx (2012)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/122159/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/122159/image.jpg&#34; alt=&#34;Box art of Cthulhu Fluxx&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;2 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Obsession (2018)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/231733/image.png&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/231733/image.png&#34; alt=&#34;Box art of Obsession&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;2 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Plant-Based Riot (2022)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/342940/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/342940/image.jpg&#34; alt=&#34;Box art of Plant-Based Riot&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;2 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Space Base (2018)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/242302/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/242302/image.jpg&#34; alt=&#34;Box art of Space Base&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;2 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Terraforming Mars (2016)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/167791/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/167791/image.jpg&#34; alt=&#34;Box art of Terraforming Mars&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;2 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Next Station: Tokyo (2023)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/380165/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/380165/image.jpg&#34; alt=&#34;Box art of Next Station: Tokyo&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;1 play&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;around-the-web&#34;&gt;Around the web&lt;/h3&gt;
&lt;h4 id=&#34;warranty-void-if-regeneratedhttpsnearzerosoftwarepwarranty-void-if-regenerated&#34;&gt;&lt;a href=&#34;https://nearzero.software/p/warranty-void-if-regenerated&#34;&gt;Warranty Void if Regenerated&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Some really cool speculative fiction about a future where all software is written by LLMs, and the social effects that may have. Unfortunately the story itself is written with an LLM, and that becomes painfully obvious about a third of the way in. By that point I was already hooked, though.&lt;/p&gt;
&lt;h4 id=&#34;my-2-step-process-for-ai-free-blogginghttpsmanuelmorealecomthoughtsmy-2-step-process-for-ai-free-blogging&#34;&gt;&lt;a href=&#34;https://manuelmoreale.com/thoughts/my-2-step-process-for-ai-free-blogging&#34;&gt;My 2-step process for AI-free blogging&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Speaking of LLM-generated text, this short piece by Manuel Moreale made me laugh. I’m by no means anti-LLM, but I really hate people publishing the output like it’s their own work. It breaks the social assumption that the writer put more effort in than the reader, and makes me wonder how much is hallucinated.&lt;/p&gt;
&lt;h4 id=&#34;25-years-of-eggshttpswwwjohn-rushcompostseggs-25-years-20260219html&#34;&gt;&lt;a href=&#34;https://www.john-rush.com/posts/eggs-25-years-20260219.html&#34;&gt;25 Years of Eggs&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;An interesting applied use of coding agents. I’m a sucker for personal statistics. I have no explicit desire to keep my receipts, or generate graphs of my egg consumption, but seeing the graphs makes me question that. The journey to get there is a great read, too.&lt;/p&gt;
&lt;h4 id=&#34;i-made-a-one-page-notebookhttpsjoelchronoxyzblogi-made-a-one-page-notebook&#34;&gt;&lt;a href=&#34;https://joelchrono.xyz/blog/i-made-a-one-page-notebook/&#34;&gt;I made a one-page notebook&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The clever paper folding is interesting, but I really like some of the small touches on the page. There’s a nice little “in reply to” callout providing context at the top of the page, you can click to rotate the image further down, and there’s a details element containing a textual version of it. It has that great ‘small web’ vibe of someone who really cares about what they’re doing.&lt;/p&gt;
&lt;h4 id=&#34;workers-who-love-synergizing-paradigms-might-be-bad-at-their-jobshttpsnewscornelledustories202603workers-who-love-synergizing-paradigms-might-be-bad-their-jobs&#34;&gt;&lt;a href=&#34;https://news.cornell.edu/stories/2026/03/workers-who-love-synergizing-paradigms-might-be-bad-their-jobs&#34;&gt;Workers who love ‘synergizing paradigms’ might be bad at their jobs&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I haven’t read the full paper, but the summary given by the article is equal parts interesting and amusing. They developed a “Corporate Bullshit Receptivity Scale”, what more is there to say?&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;It’s meant to resemble painter’s tape, but I’m not sure quite how well it works. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Modern CSS is fun</title>
        <link href="https://chameth.com/modern-css-is-fun/"/>
        <updated>2026-03-17T00:00:00Z</updated>
        <id>https://chameth.com/modern-css-is-fun/</id>
        <content xml:lang="en" type="html">&lt;p&gt;I’ve been doing a bunch of CSS tweaking recently, and keep being surprised by how nice modern CSS is to work with. As someone grey-haired enough to remember writing HTML &lt;em&gt;without&lt;/em&gt; CSS, it’s amazing to think how far along web technology has come&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. I wanted to demonstrate some of the handy bits and pieces I’ve used recently.&lt;/p&gt;
&lt;h3 id=&#34;has&#34;&gt;:has&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;:has&lt;/code&gt; selector allows you to effectively query for child elements. While &lt;code&gt;a span&lt;/code&gt; will match a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; within an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;a:has(span)&lt;/code&gt; will match an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; that contains a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;. This really shines when combined with more complex selectors, for example:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;border-radius&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;border-radius&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:has&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(+&lt;/span&gt; &lt;span class=&#34;chroma-nc&#34;&gt;.results&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:not&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:empty&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;border-bottom-left-radius&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;border-bottom-right-radius&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is part of the styling for my film search box. When the search box is presented initially it has fully rounded corners. But when it is followed by a non-empty results element, it removes the rounding on the bottom corners so that the border continues in a straight line down into the results. You can see it in action below; just enter a few characters (like “the”) to get some results:&lt;/p&gt;
&lt;div data-form-search=&#34;&#34;&gt;
    &lt;noscript&gt;JavaScript required for film search&lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;You could achieve the same effect by having JavaScript add a class to the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element, but I’ll take a CSS solution over a JavaScript solution any day.&lt;/p&gt;
&lt;h3 id=&#34;nested-rules&#34;&gt;Nested rules&lt;/h3&gt;
&lt;p&gt;You probably spotted this in the example above. It’s what finally made me switch from &lt;a href=&#34;https://sass-lang.com/&#34;&gt;SCSS&lt;/a&gt; to plain CSS. If you have a rule for &lt;code&gt;.foo&lt;/code&gt; and a rule for &lt;code&gt;.foo .bar&lt;/code&gt; you can just nest them. Not only does it save repeating yourself an awful lot, it keeps everything organised nicely. For example, the CSS for my film list embeds looks like this:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-nc&#34;&gt;.film-list&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;display&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;grid&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;header images&amp;#34;&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;description images&amp;#34;&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;meta images&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;fr&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;grid-template-rows&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;fr&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;row-gap&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;small&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;space&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;@media&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;800&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;grid-template-areas&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;header&amp;#34;&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;images&amp;#34;&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;meta&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;fr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;grid-template-rows&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;margin-top&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;medium&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;space&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-nt&#34;&gt;h3&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;font-size&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;font-size-xxlarge&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-nc&#34;&gt;.description&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Everything is wrapped up in a single bundle, including the &lt;code&gt;@media&lt;/code&gt; rules for changing the layout on smaller screens, the lovely little &lt;code&gt;&amp;amp; + &amp;amp;&lt;/code&gt; rule that adds some extra margin if there are two lists in a row, etc. The &lt;code&gt;&amp;amp;&lt;/code&gt; syntax refers to the parent selector, so &lt;code&gt;&amp;amp; + &amp;amp;&lt;/code&gt; in this case is the same as &lt;code&gt;a.film-list + a.film-list&lt;/code&gt;: it’s very handy! The best part about this is that it’s the exact same syntax as SCSS, so converting is easy&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. The styled element looks like this:&lt;/p&gt;
&lt;a class=&#34;film-list raised-box plain-link&#34; data-title=&#34;Film list&#34; href=&#34;https://chameth.com/films/lists/ranking/&#34;&gt;
  &lt;h3 class=&#34;plain-header&#34;&gt;Watched films ranked&lt;/h3&gt;
  &lt;div class=&#34;poster-stack&#34;&gt;
    &lt;img src=&#34;https://chameth.com/films/265/poster.jpg&#34; alt=&#34;Poster of Midsommar&#34;/&gt;&lt;img src=&#34;https://chameth.com/films/4/poster.jpg&#34; alt=&#34;Poster of Easy A&#34;/&gt;&lt;img src=&#34;https://chameth.com/films/97/poster.jpg&#34; alt=&#34;Poster of Hackers&#34;/&gt;&lt;img src=&#34;https://chameth.com/films/25/poster.jpg&#34; alt=&#34;Poster of The Matrix&#34;/&gt;&lt;img src=&#34;https://chameth.com/films/202/poster.jpg&#34; alt=&#34;Poster of Sinners&#34;/&gt;
  &lt;/div&gt;
  &lt;div class=&#34;description&#34;&gt;&lt;p&gt;Every film I’ve watched since I started logging, ranked.&lt;/p&gt;
&lt;p&gt;Obviously super subjective, and subject to change often and arbitrarily.&lt;/p&gt;
&lt;/div&gt;
  &lt;p class=&#34;count&#34;&gt;264 films&lt;/p&gt;
&lt;/a&gt;
&lt;h3 id=&#34;media-range-syntax&#34;&gt;Media range syntax&lt;/h3&gt;
&lt;p&gt;Once again, you might have spotted this in the previous snippet. I’m not deliberately teasing things, I promise! Back in the day, you did media queries like so:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;@media&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;min-width&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-na&#34;&gt;max-width&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;2000&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-cm&#34;&gt;/* some rules that work for screens at least 1000px wide and at most 2000px wide */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I always hated this syntax. I always got muddled up as to whether I wanted “min” or “max”, and whether they were inclusive or not. It’s easy to reason through,
but it never came naturally. Fortunately you can now just use ranges:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;@media&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;2000&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-cm&#34;&gt;/* some rules that work for screens at least 1000px wide and at most 2000px wide */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I find this style so much easier to write and understand.&lt;/p&gt;
&lt;h3 id=&#34;anchor-positioning&#34;&gt;Anchor positioning&lt;/h3&gt;
&lt;p&gt;Trying to dynamically position one element next to another used to exclusively fall within the purview of JavaScript. Fortunately anchor positioning
fixes all this. I use this in the film search field I showed above:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nc&#34;&gt;.film-search&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;anchor-name&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;film-search-box&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-nc&#34;&gt;.results&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;position&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;absolute&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;position-anchor&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;film-search-box&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;position-area&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;bottom&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;center&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;position-visibility&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;anchor-size&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This does lots of fun things. The &lt;code&gt;.results&lt;/code&gt; element is anchored to the &lt;code&gt;input&lt;/code&gt; field (via the &lt;code&gt;--film-search-box&lt;/code&gt; name), and it’s positioned on the bottom,
directly under the anchor. The &lt;code&gt;position-area&lt;/code&gt; rule describes a 3x3 grid, with the anchor at the center, so &lt;code&gt;top left&lt;/code&gt; would put it diagonally adjacent to
the anchor. Next, &lt;code&gt;position-visibility&lt;/code&gt; keeps the &lt;code&gt;.results&lt;/code&gt; element visible when the anchor &lt;em&gt;isn’t&lt;/em&gt;; otherwise when you scroll the anchor off the screen
the results would immediately vanish. Finally, the special &lt;code&gt;anchor-size()&lt;/code&gt; function makes the &lt;code&gt;.results&lt;/code&gt; element take up the same exact width as the anchor.&lt;/p&gt;
&lt;p&gt;All-in-all, this puts the results exactly where I want them, without having to deal with any JavaScript at all. I can see how it’d also be amazingly useful
trying to do tooltips or other forms of ‘floating’ content too. You can even leave the positioning up to the browser, giving it hints about which order to
try, or what property to optimise for (e.g. you can say “anchor to the left or right, whichever has more horizontal space”).&lt;/p&gt;
&lt;h3 id=&#34;attr-function&#34;&gt;attr() function&lt;/h3&gt;
&lt;p&gt;This one blew my mind a little. In some of the elements on the site, I’ve added a little label to the top. It looks something like this:&lt;/p&gt;
&lt;figure class=&#34;rating-distribution raised-box&#34; data-title=&#34;Film rating distribution&#34;&gt;
 &lt;div class=&#34;chart-container&#34;&gt;
  &lt;span class=&#34;left-label&#34;&gt;
&lt;span class=&#34;star-rating&#34;&gt;&lt;img src=&#34;https://chameth.com/star-half.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Half star&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-empty.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Empty star&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-empty.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Empty star&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-empty.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Empty star&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-empty.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Empty star&#34;/&gt;&lt;/span&gt;
&lt;/span&gt;
  &lt;svg width=&#34;200&#34; height=&#34;50&#34; viewBox=&#34;0 0 200 50&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; role=&#34;img&#34; aria-label=&#34;Film rating distribution chart&#34;&gt;
   &lt;rect x=&#34;1&#34; y=&#34;37&#34; width=&#34;18&#34; height=&#34;13&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;0.5 stars: 11 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;21&#34; y=&#34;29&#34; width=&#34;18&#34; height=&#34;21&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;1.0 stars: 18 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;41&#34; y=&#34;33&#34; width=&#34;18&#34; height=&#34;17&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;1.5 stars: 14 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;61&#34; y=&#34;31&#34; width=&#34;18&#34; height=&#34;19&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;2.0 stars: 16 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;81&#34; y=&#34;12&#34; width=&#34;18&#34; height=&#34;38&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;2.5 stars: 32 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;101&#34; y=&#34;13&#34; width=&#34;18&#34; height=&#34;37&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;3.0 stars: 31 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;121&#34; y=&#34;7&#34; width=&#34;18&#34; height=&#34;43&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;3.5 stars: 36 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;141&#34; y=&#34;0&#34; width=&#34;18&#34; height=&#34;50&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;4.0 stars: 42 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;161&#34; y=&#34;19&#34; width=&#34;18&#34; height=&#34;31&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;4.5 stars: 26 films&lt;/title&gt;
   &lt;/rect&gt;&lt;rect x=&#34;181&#34; y=&#34;4&#34; width=&#34;18&#34; height=&#34;46&#34; fill=&#34;var(--accent-colour)&#34; class=&#34;rating-bar&#34;&gt;
    &lt;title&gt;5.0 stars: 39 films&lt;/title&gt;
   &lt;/rect&gt;
  &lt;/svg&gt;
  &lt;span class=&#34;right-label&#34;&gt;
&lt;span class=&#34;star-rating&#34;&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-2&#34;/&gt;&lt;/span&gt;
&lt;/span&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;It’s meant to just be a visual flourish, not a semantic title or anything, so I initially just added a &lt;code&gt;::before&lt;/code&gt; selector to each element, customising the
&lt;code&gt;content&lt;/code&gt; to have the right value. I didn’t like the duplication, though. Now, instead, I do this:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;::before&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;attr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;data-title&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each component defines its title in a data attribute: &lt;code&gt;&amp;lt;div class=&amp;#34;raised-box&amp;#34; data-title=&amp;#34;an example&amp;#34;&amp;gt;&lt;/code&gt;, and the &lt;code&gt;attr&lt;/code&gt; function plucks it out and
puts it in the content rule. It’s worth noting that this is only widely supported for the &lt;code&gt;content&lt;/code&gt; rule, you can’t yet use it for colours or dimensions
or other things. It still feels a bit magical, though. Like you’re making a reusable, customisable component with just HTML and CSS.&lt;/p&gt;
&lt;h3 id=&#34;layers&#34;&gt;layers&lt;/h3&gt;
&lt;p&gt;I’d come across layers a few times, but I never found a need for them. It seemed like something you’d only really need with complicated design systems,
or something. Then I had a problem and layers were the perfect solution!&lt;/p&gt;
&lt;p&gt;The headings on this site have a whole bunch of CSS attached to them. Currently they look a bit like blue painter’s tape with handwriting on them.
This style is applied to all headers, and then the various places that &lt;em&gt;don’t&lt;/em&gt; want it had to manually reset everything. I got fed up with that, so
decided to add a &lt;code&gt;plain-header&lt;/code&gt; class which would “disable” the extra styling:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;h4&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;h5&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nt&#34;&gt;h6&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-cm&#34;&gt;/* common styles for all headers, regardless */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;font-family&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;Chris Hand&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;sans-serif&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;font-size&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;font-size-xxlarge&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;highlight-colour&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;margin&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;medium&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-ni&#34;&gt;space&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;line-height&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:not&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nc&#34;&gt;.plain-header&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-cm&#34;&gt;/* do fancy stuff if it _doesn&amp;#39;t_ have the .plain-header class */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;rotate&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-mf&#34;&gt;.15&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;deg&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;padding&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;smedium-space&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;font-weight&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;800&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-na&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;drop-shadow&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;rgb&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;            &lt;span class=&#34;chroma-na&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;none&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;            &lt;span class=&#34;chroma-na&#34;&gt;text-decoration-skip-ink&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-ni&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This might seem a bit backwards but I want the default to be styled, as those are far more common. I added this change,
sprinkled around some “plain-header” classes, tidied up a lot of duplicate CSS, and things mostly worked. Mostly.
Some things stopped working. In a few places the headers had slight tweaks, and they stopped working entirely.&lt;/p&gt;
&lt;p&gt;It turns out in moving the rules from a plain &lt;code&gt;h2&lt;/code&gt; selector to a &lt;code&gt;h2:not(.plain-header)&lt;/code&gt;, I’d made them more specific.
Previously a selector like &lt;code&gt;h2.special&lt;/code&gt; would have been more specific, so its properties would override those from the
less specific &lt;code&gt;h2&lt;/code&gt; selector. My first reaction was to try and hack around it. Changing all the overrides to
&lt;code&gt;body h2.special&lt;/code&gt; would make them more specific again, but I didn’t want to have to remember to do that forever more.&lt;/p&gt;
&lt;p&gt;Instead, I defined some custom layers, and put the header definitions in one:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;@layer&lt;/span&gt; &lt;span class=&#34;chroma-nt&#34;&gt;reset&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-nt&#34;&gt;links&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-nt&#34;&gt;headings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;chroma-nt&#34;&gt;layer&lt;/span&gt; &lt;span class=&#34;chroma-nt&#34;&gt;headings&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-nt&#34;&gt;h3&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;        &lt;span class=&#34;chroma-cm&#34;&gt;/* etc */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first &lt;code&gt;@layer&lt;/code&gt; rule defines some layers that will be handled in a specific order: first the “reset” layer, then
the “links” layer, then the “headings” layer, and then anything not in a layer after that. Rules in one layer don’t
have to worry about beating the specificity of rules in another layer, because they’re handled separately.&lt;/p&gt;
&lt;p&gt;Note that I couldn’t just put the headings in a layer and call it a day: their rules have to come after the CSS reset,
and after the normal link styles, as headers have a bit of extra styling for nested links. If the CSS reset weren’t in
a layer, then the &lt;code&gt;* { margin: 0; padding: 0; }&lt;/code&gt; type reset would apply over the rules from the headings layer.&lt;/p&gt;
&lt;p&gt;Using layers is definitely a bit fiddly, and is not necessary for a lot of sites, but it’s a much cleaner alternative
to ugly specificity hacking.&lt;/p&gt;
&lt;h3 id=&#34;things-im-looking-forward-to&#34;&gt;Things I’m looking forward to&lt;/h3&gt;
&lt;p&gt;There are a few things that aren’t (widely) available yet, that particularly interest me:&lt;/p&gt;
&lt;h4 id=&#34;sibling-index-and-sibling-count&#34;&gt;sibling-index() and sibling-count()&lt;/h4&gt;
&lt;p&gt;These new functions are available in WebKit and Blink based browsers, but not Firefox. They give you the index of
the element within its siblings, or the count of siblings. For the film list component above, I currently have
this abomination for the overlapping posters:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:nth-child&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nt&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;z-index&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:nth-child&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nt&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;z-index&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;calc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;133&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;overlap&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:nth-child&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nt&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;z-index&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;calc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;133&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;overlap&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:nth-child&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nt&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;z-index&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;calc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;133&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;overlap&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt;:nth-child&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nt&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;z-index&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;calc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;133&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;overlap&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These could be replaced with something like:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-na&#34;&gt;z-index&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;calc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;sibling-count&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;sibling-index&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-na&#34;&gt;left&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;calc&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;133&lt;/span&gt;&lt;span class=&#34;chroma-kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;overlap&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;sibling-index&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As an added bonus, it would scale to any number of posters. &lt;code&gt;index&lt;/code&gt; being 1-based not 0-based is a
bit unfortunate as it makes using it in calculations awkward (see &lt;code&gt;1&lt;/code&gt; offset in both of those rules!),
but it’s leagues better than writing 5 separate rules.&lt;/p&gt;
&lt;h4 id=&#34;random&#34;&gt;random()&lt;/h4&gt;
&lt;p&gt;Currently only available in Safari. There are a few places where I’d like to have slight random variations
of the style. Things like elements that are rotated slightly for aesthetics; they look a bit silly if
they’re all identically positioned. I also randomise the icons and positions of my rating stars to break
up the visual monotony. Here are a few examples:&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;star-rating&#34;&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-2&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;star-rating&#34;&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-2&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;star-rating&#34;&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-0&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-1&#34;/&gt;&lt;img src=&#34;https://chameth.com/star.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-2&#34;/&gt;&lt;img src=&#34;https://chameth.com/star-flat.png&#34; width=&#34;28&#34; height=&#34;28&#34; alt=&#34;Full star&#34; class=&#34;rot-2&#34;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Currently I do the stars by hardcoding a bunch of classes and having the backend randomly apply one when
it generates the markup for stars. Being able to do it in CSS would be great, though.&lt;/p&gt;
&lt;h4 id=&#34;mixins&#34;&gt;Mixins&lt;/h4&gt;
&lt;p&gt;This one’s so far off it’s not even listed on &lt;a href=&#34;https://caniuse.com/&#34;&gt;caniuse.com&lt;/a&gt; yet. Mixins are another handy feature of
SCSS, that allow you to define reusable blocks of rules, then import them when needed:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;@mixin&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt; fancy-background&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-na&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-cm&#34;&gt;/*...&lt;/span&gt;&lt;span class=&#34;chroma-c&#34;&gt;*/&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nc&#34;&gt;.some-element&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;@include&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt; fancy-background&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-nn&#34;&gt;#other-element&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;    &lt;span class=&#34;chroma-k&#34;&gt;@include&lt;/span&gt;&lt;span class=&#34;chroma-nd&#34;&gt; fancy-background&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This would be particularly useful if you can’t easily control the markup to add classes to everything. For example, my
footnotes are rendered by a markdown plugin, and don’t easily have a way to add extra classes to them. To style it the
same as another element, I currently duplicate a bunch of rules between them both. Mixins would allow me to define those
rules once, and then import them in both places.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Aside from JavaScript, which seems to just endlessly reinvent new frameworks and ways to make the most sprawling dependency tree possible. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;It also means that if your website’s syntax highlighting library doesn’t seem to understand nested rules, you can just pretend your perfectly valid CSS is actually SCSS and it’ll magically work. Grumble, grumble. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>An interesting Tailscale + Docker gotcha</title>
        <link href="https://chameth.com/tailscale-docker-gotcha/"/>
        <updated>2026-01-29T00:00:00Z</updated>
        <id>https://chameth.com/tailscale-docker-gotcha/</id>
        <content xml:lang="en" type="html">&lt;p&gt;As I’ve &lt;a href=&#34;https://chameth.com/how-i-use-tailscale/&#34;&gt;written&lt;/a&gt; &lt;a href=&#34;https://chameth.com/avoiding-the-consequences-of-dumb-laws-with-tailscale/&#34;&gt;about&lt;/a&gt; &lt;a href=&#34;https://chameth.com/exposing-game-servers-over-tailscale/&#34;&gt;before&lt;/a&gt;, I use &lt;a href=&#34;https://tailscale.com/&#34;&gt;Tailscale&lt;/a&gt; for a lot of things. I thought I had it set up in a reasonably secure manner, but I recently noticed a problem.&lt;/p&gt;
&lt;p&gt;I use Tailscale’s ACLs to limit what each node can access, based on the tags I apply to it. So an &lt;code&gt;app&lt;/code&gt; node can’t access anything via Tailscale, while an &lt;code&gt;integration&lt;/code&gt; or &lt;code&gt;server&lt;/code&gt; node can access things tagged with either &lt;code&gt;app&lt;/code&gt; or &lt;code&gt;integration&lt;/code&gt;. This is expressed pretty simply in the Tailscale ACL JSON:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tagOwners&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-c1&#34;&gt;// Servers that can be SSH&amp;#39;d into
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tag:server&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-c1&#34;&gt;// Applications that are exposed on tailscale but never connect out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tag:app&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-c1&#34;&gt;// Things which talk to other services over tailscale (connecting to apps etc)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tag:integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;grants&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-c1&#34;&gt;// Users can access everything
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;autogroup:member&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;dst&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;ip&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-c1&#34;&gt;// Servers and integrations can access integrations and apps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:server&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;dst&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:app&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;ip&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Over the past week I’ve been setting up a private &lt;a href=&#34;https://forgejo.org/&#34;&gt;Forgejo&lt;/a&gt; instance behind Tailscale, complete with an actions runner that runs things using a docker-in-docker container. I didn’t want the runner knowing anything about Tailscale, so I had it configured to speak to Forgejo direct over HTTP (&lt;code&gt;forgejo:3000&lt;/code&gt;) instead of using full Tailscale HTTPS URL that I use when accessing it (&lt;code&gt;http://git.example-net.ts.net/&lt;/code&gt;)&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Everything was going fine, until I forgot to do that translation… and it worked. My Forgejo action runners could access anything on my tailnet. I run several things on Tailscale that just have authentication turned off, on the basis that only authorised devices can access them. Things like the admin interface for this website. I definitely didn’t intend for any workflow I run on my git server to have access to edit my website!&lt;/p&gt;
&lt;p&gt;This wasn’t just limited to Forgejo, either. Any docker container I was running could access the tailnet. In hindsight it’s fairly obvious why: the host is running Tailscale, connected as a node tagged with my &lt;code&gt;server&lt;/code&gt; tag. That creates a &lt;code&gt;tailscale0&lt;/code&gt; interface, and automagically sets up iptables rules to route Tailscale traffic over the interface. Docker also automagically sets up iptables rules to bridge traffic, and apparently these two sets of rules interact in such a way that traffic from Docker containers is allowed to route via the &lt;code&gt;tailscale0&lt;/code&gt; interface.&lt;/p&gt;
&lt;p&gt;I say it’s fairly obvious in hindsight — there’s no reason why Docker would special case any particular host interface after all — but it still feels pretty surprising. Because both bits of software inject their own iptables rules, I never really had a good mental model for how they interact. The host Tailscale node was a completely separate building block to Docker. It would be a pain to use either of them if they didn’t do these rules, but it’s also one of the reasons I don’t really like “magical” things&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;There are lots of ways to fix this, but none of them feel particularly great. You can configure both Tailscale and Docker to not automatically fiddle with iptables and handle the rules yourself, but I really hate dealing with iptables&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. As a stopgap I did hold my nose and add some iptables rules to drop traffic to the &lt;code&gt;tailscale0&lt;/code&gt; interface if it originated from the IP ranges that Docker was configured to use:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 192.168.0.0/16 -o tailscale0 -j DROP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 172.17.0.0/12 -o tailscale0 -j DROP
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;DOCKER-USER&lt;/code&gt; chain is a nice little escape hatch; it comes before the main auto-generated &lt;code&gt;DOCKER&lt;/code&gt; chain, and Docker leaves the rules in it alone.&lt;/p&gt;
&lt;p&gt;So I added these rules, and felt pretty good about myself, and then… everything started breaking in weird ways. After some debugging I realised the problem was DNS&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;. The server’s DNS resolver is &lt;code&gt;100.100.100.100&lt;/code&gt;, a special Tailscale address. This is so that it can resolve tailnet hostnames via &lt;a href=&#34;https://tailscale.com/kb/1081/magicdns&#34;&gt;MagicDNS&lt;/a&gt; (and so I don’t have to configure my custom DNS servers manually on each device; Tailscale does it for me). My new iptables rules inadvertently dropped all the DNS packets coming from docker containers. D’oh.&lt;/p&gt;
&lt;p&gt;Obviously the solution here is to double down and add MORE iptables rules:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 192.168.0.0/16 -d 100.100.100.100 -o tailscale0 -j ACCEPT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 172.17.0.0/12 -d 100.100.100.100 -o tailscale0 -j ACCEPT
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This got DNS working again, but it all feels a bit gross. Not least because to actually make these persist you need to use &lt;code&gt;iptables-save&lt;/code&gt;, and then you also get all the rules that both Docker and Tailscale have inserted. I came across &lt;a href=&#34;https://github.com/giangi/iptables-docker-filter&#34;&gt;a script&lt;/a&gt; to filter out the Docker ones, but… yuck&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I realised a cleaner idea might just be to lock down what &lt;code&gt;server&lt;/code&gt; tagged nodes could access within Tailscale itself. That way I can avoid touching iptables at all. It’s handy to be able to &lt;code&gt;curl&lt;/code&gt; services from the host when debugging, but it’s not really necessary. So I removed that access, and… stuff broke again. I’m using my Forgejo instance as a registry for some of the docker images I run, so the docker daemon needs to be able to reach it. I ended up making a new tag for &lt;code&gt;infrastructure&lt;/code&gt;, which can be accessed from &lt;code&gt;server&lt;/code&gt; devices. This does still allow all the docker containers to reach Forgejo, but I already have it set up with appropriate access controls and public/private repository splits. Forgejo is a service designed to run publicly, so this seems a reasonable trade-off for convenience. I used the &lt;code&gt;tests&lt;/code&gt; feature of Tailscale’s ACL config to make sure I’d got the rules right:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tests&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-c1&#34;&gt;// Servers can only access infrastructure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;   &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:server&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;proto&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:infrastructure:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;deny&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;100.84.16.43:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;me@example.com:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:server:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:app:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:integration:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The whole situation still feels a bit messy. If I ever get around to switching to nftables I might loop back and manually craft some rules for routing traffic, instead of leaving Tailscale and Docker to do their own thing.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I discovered later on that logging into the container registry at &lt;code&gt;forgejo:3000&lt;/code&gt; actually issued a redirect to &lt;code&gt;https://git.example-net.ts.net/&lt;/code&gt; so this was all basically for naught… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I didn’t use Tailscale’s MagicDNS for a long time just because the word “magic” put me off. Only when I eventually got around to learning how it worked, and seeing that it wasn’t really that magical under the hood, did I change my mind. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;nftables seems far better in lots of ways, but I can’t really be bothered migrating. Maybe next time I reimage the server for whatever reason… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;It’s always DNS… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;Again, nftables would almost certainly help here. It actually has (gasp) configuration files. But again, I really didn’t want to spend the time migrating. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Adventures in IPv6 routing in Docker</title>
        <link href="https://chameth.com/ipv6-docker-routing/"/>
        <updated>2022-10-24T00:00:00Z</updated>
        <id>https://chameth.com/ipv6-docker-routing/</id>
        <content xml:lang="en" type="html">&lt;p&gt;One of the biggest flaws in Docker’s design is that it wasn’t created with IPv6 in mind. Out of the box Docker assigns
each container a private IPv4 address, and they won’t be able to reach IPv6-only services. While incoming connections
might work, the containers won’t know the correct remote IP address which can cause problems for some applications.
This situation is obviously suboptimal in the current day and age. It’s a bit like not supporting HTTPS on a website —
you might not have any issues because of it immediately, but you’re fighting against the currents of progress and are
making life worse for your users.&lt;/p&gt;
&lt;p&gt;Thankfully, it’s now relatively easy to make Docker behave a lot nicer. The
&lt;a href=&#34;https://github.com/robbertkl/docker-ipv6nat&#34;&gt;docker-ipv6nat&lt;/a&gt; project has been around since 2016, and uses an IPv6
overlay network and some iptables magic to route traffic to and from containers in a sensible fashion. It uses NAT
to emulate the behaviour Docker employs for IPv4 traffic; while using NAT with IPv6 is an anathema, I think it makes
sense for containers. You could give each container a publicly routable IPv6 address, but that brings with it a lot
of headaches: you’re basically going to be forced to implement service discovery and some kind of DNS management to
deal with the fact that your containers will be popping up on randomly assigned IP addresses. That is completely
overkill for people running a small number of services on one or two physical boxes; and if it’s not overkill for you
then you’re probably already looking at more complicated orchestration solutions like Kubernetes.&lt;/p&gt;
&lt;p&gt;More recently, similar functionality has been built into the Docker daemon itself. You can now
&lt;a href=&#34;https://docs.docker.com/config/daemon/ipv6/&#34;&gt;edit the config file to enable ipv6&lt;/a&gt; and each container will be
assigned an address in the range specified when it uses the default bridge network. This gives more-or-less the same
functionality of docker-ipv6nat — you lose a little flexibility as you can’t disable IPv6 on the default bridge, but
that’s a very worthy trade for having the functionality built-in.&lt;/p&gt;
&lt;p&gt;So far this all seems very simple. Hardly worthy of being called an “adventure”. Enter stage left: the wicked witch of
destination address selection…&lt;/p&gt;
&lt;!--more--&gt;
&lt;h3 id=&#34;destination-address-selection-and-you&#34;&gt;Destination address selection and you&lt;/h3&gt;
&lt;p&gt;When a computer program tries to connect to an address such as &lt;code&gt;google.com&lt;/code&gt;, it first resolves it in to an IP address.
That’s DNS 101, but what happens if the address resolves to multiple IP addresses? For example, &lt;code&gt;google.com&lt;/code&gt; resolves
to both &lt;code&gt;142.250.74.206&lt;/code&gt; and &lt;code&gt;2a00:1450:4001:82b::200e&lt;/code&gt;. You might just assume there’s a simple
“prefer IPv4 / prefer IPv6” toggle somewhere that decides, but it’s actually a lot more complicated. With IPv6, devices
are likely to have many addresses - a link-local address, a unique local address, a normal public address, various
privacy addresses, and so on. To deal with this, a number of RFCs define a series of rules that most implementations
follow. These are called the &lt;em&gt;destination address selection rules&lt;/em&gt;. &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6724&#34;&gt;RFC6724&lt;/a&gt;
gives the rules as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Avoid unusable destinations&lt;/li&gt;
&lt;li&gt;Prefer matching scope&lt;/li&gt;
&lt;li&gt;Avoid deprecated addresses&lt;/li&gt;
&lt;li&gt;Prefer home addresses&lt;/li&gt;
&lt;li&gt;Prefer matching label&lt;/li&gt;
&lt;li&gt;Prefer higher precedence&lt;/li&gt;
&lt;li&gt;Prefer native transport&lt;/li&gt;
&lt;li&gt;Prefer smaller scope&lt;/li&gt;
&lt;li&gt;Use the longest matching prefix&lt;/li&gt;
&lt;li&gt;Otherwise, leave the order unchanged&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Applying these rules will re-order the list of IP addresses such that (in theory) the most likely one to work will be
first. Most of them are fairly niche rules; the ones that do the heavy lifting are rules 5 and 6, which rely on a policy
table to make their decisions. The policy table ‘SHOULD’ be configurable by system administrators to allow them to tweak
how traffic is routed. In the absence of an admin-provided policy table, the RFC gives the following defaults:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Precedence&lt;/th&gt;
&lt;th&gt;Label&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::1/128&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Loopback address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::/0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Any IPv6 address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::ffff:0:0/96&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;IPv4 addresses mapped as v6 addresses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2002::/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6-to-4 gateways&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2001::/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Toredo tunnels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fc00::/7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;Unique Local Addresses (ULAs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::/96&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;IPv4 compatible addresses (deprecated)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fec0::/10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Site-local addresses (deprecated)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3ffe::/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6bone (deprecated)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The policy table is a bit complex, but you can see that normal IPv6 addresses are preferred (have a higher precedence)
over IPv4 addresses, which are preferred over the various tunnels, local addresses, and various deprecated ranges.&lt;/p&gt;
&lt;p&gt;We can see the result of this when I run &lt;code&gt;ping google.com&lt;/code&gt; on a box that has a native IPv6 connection as well as a
native IPv4 connection:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;PING google.com(fra07s29-in-x200e.1e100.net (2a00:1450:4001:802::200e)) 56 data bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra24s01-in-x0e.1e100.net (2a00:1450:4001:802::200e): icmp_seq=1 ttl=119 time=5.11 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra24s01-in-x0e.1e100.net (2a00:1450:4001:802::200e): icmp_seq=2 ttl=119 time=5.28 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra07s29-in-x200e.1e100.net (2a00:1450:4001:802::200e): icmp_seq=3 ttl=119 time=5.31 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;--- google.com ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;3 packets transmitted, 3 received, 0% packet loss, time 2003ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;rtt min/avg/max/mdev = 5.114/5.235/5.311/0.086 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The address selection in this instance has been a result of rule 6: the IPv6 address has a higher precedence (40) than
the IPv4 address (35).&lt;/p&gt;
&lt;p&gt;However, if I run the same command in an IPv6-enabled Ubuntu container then it seems to prefer the IPv4 address:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;PING google.com (172.217.16.206) 56(84) bytes of data.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s08-in-f206.1e100.net (172.217.16.206): icmp_seq=1 ttl=59 time=4.86 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s08-in-f14.1e100.net (172.217.16.206): icmp_seq=2 ttl=59 time=4.86 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s08-in-f14.1e100.net (172.217.16.206): icmp_seq=3 ttl=59 time=5.03 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;--- google.com ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;3 packets transmitted, 3 received, 0% packet loss, time 2003ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;rtt min/avg/max/mdev = 4.860/4.916/5.027/0.078 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If I force &lt;code&gt;ping&lt;/code&gt; to use IPv6 with the &lt;code&gt;-6&lt;/code&gt; flag then it works the same as on the host, but when left to its own devices
it prefers IPv4. What’s going on there? The key difference between the Docker container and the host is that the host’s
network interfaces have public addresses, but the container has a private IPv4 address (&lt;code&gt;172.19.0.7&lt;/code&gt;) and a private
IPv6 address (&lt;code&gt;fd00:dead:beef::7&lt;/code&gt;). My first reaction to this was to think “Ah yes, fc00::/7 has a lower precedence
than native IPv4, that makes sense”, but that’s not quite right. These are the &lt;em&gt;destination&lt;/em&gt; address selection rules;
rule 6 doesn’t care about the source addresses. This is actually rule 5 at work: the label of source IPv6 address is
&lt;code&gt;13&lt;/code&gt;, but the label of the destination address is &lt;code&gt;1&lt;/code&gt;; meanwhile both the source and destination IPv4 addresses are &lt;code&gt;4&lt;/code&gt;.
This sorts the IPv4 address before the IPv6 one, and rule 6 becomes irrelevant.&lt;/p&gt;
&lt;h3 id=&#34;adjusting-the-policy-table&#34;&gt;Adjusting the policy table&lt;/h3&gt;
&lt;p&gt;Thankfully, the RFC says the policy table should be configurable by system administrators, so those of us who are doing
unorthodox things like NAT’ing IPv6 can customise the behaviour to fit our weird environments. The configuration is
done via the &lt;a href=&#34;https://man.archlinux.org/man/gai.conf.5.en&#34;&gt;/etc/gai.conf&lt;/a&gt; file (‘gai’ standing for &lt;code&gt;getaddrinfo&lt;/code&gt;, the
function in the standard library responsible for dealing with all these rules). The &lt;code&gt;gai.conf&lt;/code&gt; file by default (if it
exists) will likely just contain comments and examples; if there are no uncommented “label” or “precedence” lines then
the library will use its built-in defaults based on the RFC requirements.&lt;/p&gt;
&lt;p&gt;To make our container happy, we need to cause &lt;code&gt;fd00::/8&lt;/code&gt; to have the same label as a public IPv6 address. To do this we
can uncomment the default labels in &lt;code&gt;gai.conf&lt;/code&gt; and then add a single extra line, like so:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::1/128       0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::/0          1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label 2002::/16     2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::/96         3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::ffff:0:0/96 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label fec0::/10     5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label fc00::/7      6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label 2001:0::/32   7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-gi&#34;&gt;+label fd00::/8      1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because &lt;code&gt;fd00::/8&lt;/code&gt; has a longer prefix than &lt;code&gt;fc00::/7&lt;/code&gt; it will match our addresses and give them a label of &lt;code&gt;1&lt;/code&gt;, the
same as a public IPv6 address would get. This makes rule 5 leave it alone, and the default precedence table used by
the standard library will put the IPv6 address above the IPv4 address. (They don’t bother giving &lt;code&gt;fc00::/7&lt;/code&gt; a separate
precedence as listed in the RFC because rule 5 would have already de-prioritised those addresses, as we discovered.)&lt;/p&gt;
&lt;p&gt;Making this small change to the &lt;code&gt;gai.conf&lt;/code&gt; file in our Ubuntu container makes it start preferring the IPv6 address
for &lt;code&gt;google.com&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;PING google.com(fra16s65-in-x0e.1e100.net (2a00:1450:4001:806::200e)) 56 data bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra15s29-in-x0e.1e100.net (2a00:1450:4001:806::200e): icmp_seq=1 ttl=118 time=5.00 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra15s29-in-x0e.1e100.net (2a00:1450:4001:806::200e): icmp_seq=2 ttl=118 time=5.10 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s65-in-x0e.1e100.net (2a00:1450:4001:806::200e): icmp_seq=3 ttl=118 time=5.08 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;--- google.com ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;3 packets transmitted, 3 received, 0% packet loss, time 2004ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;rtt min/avg/max/mdev = 5.002/5.058/5.098/0.040 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A fairly complicated problem, but a simple fix!&lt;/p&gt;
&lt;h3 id=&#34;but-wait-theres-more&#34;&gt;But wait, there’s more…&lt;/h3&gt;
&lt;p&gt;Unfortunately, this fix won’t work on containers that use alpine. And that is a &lt;em&gt;lot&lt;/em&gt; of containers. Alpine uses
&lt;a href=&#34;https://musl.libc.org/&#34;&gt;musl&lt;/a&gt; as its standard library, rather than the much more common
&lt;a href=&#34;https://www.gnu.org/software/libc/&#34;&gt;glibc&lt;/a&gt;. There is very little documentation on the subject, but if you browse
the source code for musl you will see that it doesn’t implement any way at all to configure the policy tables. In
&lt;a href=&#34;https://git.musl-libc.org/cgit/musl/tree/src/network/lookup_name.c?id=63402be229facae2d0de9c5943a6ed25246fd021&#34;&gt;network/lookup_name.c&lt;/a&gt;
we can see the sorting logic:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-cm&#34;&gt;/* The following implements a subset of RFC 3484/6724 destination
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * address selection by generating a single 31-bit sort key for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * each address. Rules 3, 4, and 7 are omitted for having
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * excessive runtime and code size cost and dubious benefit.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * So far the label/precedence table cannot be customized. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;cnt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sockaddr_in6&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_scope_id&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;scopeid&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_port&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;65535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_port&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;65535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;socklen_t&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\xff\xff&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\xff\xff&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dpolicy&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;policyof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dscope&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;scopeof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dlabel&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dpolicy&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dprec&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dpolicy&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;prec&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;prefixlen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;SOCK_CLOEXEC&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;IPPROTO_UDP&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_USABLE&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;getsockname&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dscope&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;scopeof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_MATCHINGSCOPE&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dlabel&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;labelof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_MATCHINGLABEL&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-n&#34;&gt;prefixlen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;prefixmatch&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dprec&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_PREC_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dscope&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_SCOPE_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;prefixlen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_PREFIX_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;MAXADDRS&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_ORDER_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sortkey&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nf&#34;&gt;qsort&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;cnt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;addrcmp&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see if the address labels match, the sort key is adjusted using the &lt;code&gt;DAS_MATCHINGLABEL&lt;/code&gt; constant. But where
do the labels come from? For that we need to investigate the &lt;code&gt;policyof&lt;/code&gt; func:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;chroma-kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;chroma-kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;chroma-kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;prec&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\xff\xff&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;35&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\x20\2&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\x20\1&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\xfc&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xfe&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;13&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cp&#34;&gt;#if 0&lt;/span&gt;&lt;span class=&#34;chroma-c&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	/* These are deprecated and/or returned to the address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	 * pool, so despite the RFC, treating them as special
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	 * is probably wrong. */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	{ &amp;#34;&amp;#34;, 11, 0xff, 1, 3 },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	{ &amp;#34;\xfe\xc0&amp;#34;, 1, 0xc0, 1, 11 },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	{ &amp;#34;\x3f\xfe&amp;#34;, 1, 0xff, 1, 12 },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-cm&#34;&gt;/* Last rule must match all addresses to stop loop. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;40&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;policyof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;in6_addr&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;memcmp&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		    &lt;span class=&#34;chroma-o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the &lt;code&gt;policyof&lt;/code&gt; func simply uses the &lt;code&gt;defpolicy&lt;/code&gt; array to find the policy that applies to an address. This &lt;code&gt;defpolicy&lt;/code&gt;
array contains a number of hardcoded entries which correspond exactly to the ones provided in the RFC. The one causing
us problems is &lt;code&gt;{ &amp;#34;\xfc&amp;#34;, 0, 0xfe, 3, 13 }&lt;/code&gt; which matches &lt;code&gt;fc00::/7&lt;/code&gt; addresses.&lt;/p&gt;
&lt;p&gt;Unfortunately, without recompiling musl from source there’s not much we can do to address this directly. The only way
we can make the containers work as desired is to give them a different address range. Ideally this would be a range
that you control and that is otherwise not used, but there’s a good chance you won’t have such a range. One possible
alternative is the &lt;code&gt;2001:db8::/32&lt;/code&gt; range which is reserved for documentation purposes. This doesn’t feature in any of
the policy tables, so is treated like a normal public IPv6 address. It doesn’t feel great to misuse a reserved range
like that, but it’s probably the least of all evils, at least until musl allows configuring the policy table.&lt;/p&gt;
</content>
    </entry>
</feed>
