Work Text:
Don't panic!
🪐🤣
CONTENTS:
Intro.
Multichapter fics viewed in “Chapter by Chapter” mode
Multichapter fics viewed in “Entire Work” mode
Single-chapter fics viewed in default
Single-chapter fics viewed in “Entire Work” mode
Single-chapter fics viewed in “Chapter by Chapter” mode
Timestamps
Old testing results
Points to ponder, Pinky
NOTE:
If you have turned off Creator's Style (manually or automatically), then you might want to turn it back on for this work. I've tried to keep the layout and wording as clear as I can for TTS screen readers and braille readers (hell, I even separated [as usual] the Table of Contents into more-manageable groupings for anyone trying to thumb things on a tiny viewport such as a 'phone), so the color coding shouldn't be necessary, but if you're reading visually (or color-coding cues are otherwise apparent to you) and the palette differs in brightness sufficiently against any given form of color blindness, then having them present could help draw your attention to certain pieces of data more obviously (not simply for their colors being different, but also by blue being info, green being something useful, notepad-yellow-ish being a note, bright yellow being caution, red being warning, etc.).
If this paragraph has a double-border and light green background, then you should be G2G.
What you see below is the basics for demonstrating each rule. The declarations aren't designed to be pretty, since I'm not trying to dazzle you with the actual effects themselves, they're just some background colors and borders that change in accordance with certain conditions so that you can see them and test them for yourself.
What you do with them is up to you. Add different backgrounds and box-shadows to each chapter of every work (that is: establish some rule like those below, such as the very first rule named in the first section [multichapter fics viewed in default chapter-by-chapter mode #workskin:is(:has(ul.user.navigation.actions li a[href*='0%2Fchapters']) *) {, which in this example would check to see if the current chapter's id number ends with a "0" — though as-is, this rule would then apply your declaration(s) to the entire work, so you might want to get more specific by adding some element(s) between those last two characters of ) {, such as ) #workskin {, ) .preface.group {, ) #chapters {, ) .userstuff {; there are a lot of options, but I go into their details in Targeting specific AO3 work sections (not site) with CSS effects ] and give it some declaration(s) [such as outline, border: 2px solid black; {and borders have other options}, box-shadow {MDN has a good write-up, which also does a nice job with the inset, as has W3's write-up — though with box-shadow, you might want to add a special rule of its own of #work-skin.wrapper { overflow-y: visible !important; } in order to give the effect some breathing room}, background, and/or color [that's the written words' ink color, if you're new to this]), make a fancy border with lace and flowers, it's all good (CAUTION: If using all of this stuff in a site skin, remember that authors sometimes make magic too, and your choices can conflict with theirs — I had a reader who missed a lot of material in one of my CSS-heavy tutorials because they were reading with a site skin that made all written material become rainbow colored).
They will function in a work skin for you as an author who'd like to cause these effects but doesn't want to write a whole new skin for every single work; they will function for you in a site skin as a reader who like a little simple variety in their reading, just enough to keep things popping without having to go overboard — and bonus: in either case, the effects won't be random with every page refresh or new visit to a prior-read work (except if you're using a timestamp-based rule and the work has since been edited), instead staying calmly predictable each time for a given work / chapter / view combo.
You can drop all, some, or none of these into a work skin or a site skin, and they'll function (well, if you drop none of them in, then... technically [thank you, Futurama ] they'd still function for everyone else, just not for you 😆) since none of them are aimed at parts of the page outside of the work skin — however, I did not copypaste the site skin rules from below and test across multiple works as a work skin, I tested only a couple of single-chapter works as a trial run, and it's a mixed result (so yes, this demonstrates how to for work skins, but is fully functional as-is only for site skin purposes); I'm working on that part, tough, so will update with any changes needed for work skin application. If you drop them into a site skin, then of course you can target the #outer.wrapper, #inner.wrapper, #main, div.work, metadata block (.work.meta.group), header, footer, #work-skin.wrapper, etc. (to figure out which element you're looking at in fics' pages outside of the work itself, so that you can target those things [in which case you would obviously not want their rules to end with ... #workskin ... { 😆], cf. this section on “Inspect [Element]” in my fonts tutorial), instead of only the work material itself, and had at first kept it simple so that authors could jump right in with it for their work skins and readers have a decent starting point for site skin results of their own devise, but for testing purposes had to start with site skin only (only afterward copypasting the whole as a work skin and discovering the mixed results).
Between the final glyphs of the work_id, chapter_id, and timestamp, that's 10x10x10 = 1,000 possible effect combos (and another x10x10 if using the work_id and chapter_id initial glyphs, which might not be a great idea, and I'd really avoid bothering with the timestamp's initial glyph's x10, due to the strong skew of values' probability distribution with initial glyphs in all of these cases).
If you've dug through my CSS Abuse and HTML Tryhard collection, then you already know how one can apply the meta CSRF authorization token glyphs to spectacular ends in puzzles and playable games. Those run on a set of 64 possible initial glyphs {a...z, A...Z, 0...9, -, _} and 4 final glyphs {A, g, Q, w} as the RNG seeds (cf. e.g.: RNG in site skins — which, on a tangent, takes a different angle for identifying the work_id using #workskin:is(:has(form[action^="/works/73829211"]) *), for which you might find some use in pursuing the work-identifying rules below; for clarification, that CSS looks for a work's <form action="/works/... in the <div id="bookmark_form_placement" class="wrapper toggled"> part of the page source), each changing with most page refreshes (NB: Mewzmodeus pioneered their identification and active use, I just used them for RNG [TL;DR: click the link for more details, and there's a short who-did-what in this comment thread; I'd like credit for parts of stuff that I did do, but I don't want credit for parts that were others' doings]).
The ones here stay a set value over time (work id and chapter id) or typically don't change (timestamp: if you add / subtract / rearrange chapters, or edit the tags or work skin or actual material content of a chapter, then the timestamp changes), but can be leveraged in the same fashion (though greatly limited if applied that way) — essentially statically deterministic effects randomized per work_id, chapter_id, and/or timestamp, rather than dynamically randomized on the fly with each refresh by the meta CSRF token.
Incidentally, in my site skin test, I specifically open it with a general reminder to myself:
.NOTE_re_DETERMINE_URL_and_VIEW ################################################################ {
content: " /// *
The key to the set of rules immediately below, and the next several sets following it, is that ul.user.navigation.actions herein (which is the header greeting logout section of the rendered DOM and the page source) identifies uniquely a link for a given work slug in the URL — or if there are chapters, then the work directory and chapter slug in the URL — and that %3F%26view_full_work%3Dtrue checks to see if the work is being viewed in Entire Work mode (and what the work URL final digit is, preceding that part), and that the presence or absence of %2Fchapters (and what the chapter URL final digit is, preceding that part) in the source ascertains whether there are further chapters vs. being a single-chapter work.
I used the containing asterisk in most cases, rather than an ending dollar sign, because some parts of URLs can get a little mixed up, depending upon how one arrives at them.
* ///";
}
Multichapter fics viewed in “Chapter by Chapter” mode Contents ↑
i.e.: single chapter at a time mode... the default
MC by ch
(hint: click/tap to expand details)
Below is the site skin rule subset. I'm still trying to clear up the work skin side of the house.
.NOTE_re_MULTI_in_simple_singleton_view ################################ {
content: " /// *
This set is to give individual border colors to MULTI-chapter WORK ID ending with a given number 0...9, in SINGLE CHAPTER VIEW.
For example, 0%2Fchapters affects any multi-chapter work whose work directory ends in 0, while 1%2Fchapters does the same for any work directory that ends in 1.
I chose some fairly strikingly different websafe colors from https://www.w3schools.com/colors/colors_names.asp as the starting point. * ///";
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='0%2Fchapters']) *) {
border: 2px solid black;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='1%2Fchapters']) *) {
border: 2px solid maroon;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='2%2Fchapters']) *) {
border: 2px solid crimson;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='3%2Fchapters']) *) {
border: 2px solid orange;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='4%2Fchapters']) *) {
border: 2px solid yellow;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='5%2Fchapters']) *) {
border: 2px solid green;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='6%2Fchapters']) *) {
border: 2px solid blue;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='7%2Fchapters']) *) {
border: 2px solid navy;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='8%2Fchapters']) *) {
border: 2px solid purple;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='9%2Fchapters']) *) {
border: 2px solid RebeccaPurple;
}
— — —
NB: What happens when loading multi-chapter (or single-chapter works, for that matter), but removing the /works/xxxxxxxx portion of the URL? Then you get whatever effects your work/site skin causes for chapters (since your browser will see the presence of the chapter in the page), but not the work-based effects (because that aspect of the URL isn't present in the page anymore).
As well, you could also search out the work_id in show_comments_link and show_comments_link_top buttons (ditto for the presence of chapter_id only when in MC’s chapter reading or SC’s /navigate chapter view [that same view can be used on multichapter, of course, it's just that this is the only way to access single-chapter works' specific-chapter numbers]... as long as there are any comments to be shown for that chapter).
For that matter, you could go overboard and style each div. Source shows <div class="chapter" id="chapter-2"> = rendered DOM’s div#chapter-2.chapter, so maybe something to the effect of (I'd need to play with this in order to be certain)
:is(:has([id^="chapter-ONE_OF_NINE_POSSIBLE_INITIAL_GLYPHS_HERE"]) *) {
border: 3px solid COLOR_HERE;
}
:is(:has([id$="chapter-ONE_OF_TEN_POSSIBLE_FINAL_GLYPHS_HERE"]) *) {
background: COLOR_HERE;
}
or hell, maybe something like simply body:has(#chapters > .chapter:nth-child(10n)), for {10n, 10n+1, 10n+2, ..., 10n+9}? Much cleaner.
Multichapter fics viewed in “Entire Work” mode Contents ↑
MC view_full
This one comes with an example of what not to do. I experimented with the example rule that begins this set, trying :has('id="chapter-2"') instead of :has(#chapter-2), and found that it failed (hence the _FAILS_TO_EXCLUDE at the end of that row and the whole red ink on pinkish background highlighting) — so now that I know, you do to, and you won't be left wondering.
When I dropped this tutorial, I simply gave these rules what I had been using as basic tests — they all ended with ...#workskin { border: 3.5px dashed red;, but since I was in here to edit-in the fixed single chapters' default view's ("Berk" view's) rule construction, I figured that I might as well clean this section up a bit, too, so that you can more easily see when one effect or another actually kicks in and precisely why, rather than than the useless same-rule-for-all that's only any good for basic testing, and now they read ...h3.byline.heading { border: 3.5px dashed [Insert_each_declaration's_specific_color_here]; (way better differentiation), and I moved my color choices ahead by 2 increments to try to keep them from blending too much with other rule subsets' same-glyphs' colors.
Unlike the prior rule set, for multichapter in default (one chapter at a time) view, this one it matters whether your paste to a site skin as-is versus to a work skin... sorta: you don't need to add the #workskin to the front of the rule, of course, since AO3 will do that for you in a work skin, but you need to pay attention because the exact structure is slightly different (see REM note).
.NOTE_re__MULTI_in_doom_scroll_mode ################################ {
content: " /// *
This set is to give individual border colors to MULTI-chapter WORK ID ending with a given number 0...9, in ENTIRE WORK MODE.
For example, 0%3F%26view_full_work%3Dtrue affects any multi-chapter work whose work directory ends in 0, while 1%3F%26view_full_work%3Dtrue does the same for any work directory that ends in 1.
In my testing, I originally chose websafe colors again, same source, aiming for neon variants this time. Here they are only red, but in my test set they were LightGrey, #666, #AA6666, #D47084, #E6B966, #E6E666, #66A666, #6666E6, #6666A6, #A666A6, and #9980B3, in case you happen to wonder.
These originally containedul.user.navigation.actions li a[href..., since it looks at the logout button, but it turned out not to be needed, hence the truncation that you see below (which I discovered while troubleshooting the work skin's mixed results that came from being copypasta of the site skin form below: it was OK to leave that in as a site skin, but using the untruncated form in the work skin showed the path's unnecessity).
What is below is for SITE SKINS.
For WORK SKINS, you need a slightly different structure: #workskin:is(:has(a[href*='0%3F%26view_full_work%3Dtrue']) *) .byline, where you will note that there is a distinct lack of the :has(#chapter-2) thing right before the end.
* ///";
}
:is(:has(ul.user.navigation.actions li a[href*='0%3F%26view_full_work%3Dtrue']) *):has('id="chapter-2"') #workskin_FAILS_TO_EXCLUDE {
border: 3.5px dashed black;
}
:is(:has(a[href*='0%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed purple;
}
:is(:has(a[href*='1%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed RebeccaPurple;
}
:is(:has(a[href*='2%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed black;
}
:is(:has(a[href*='3%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed maroon;
}
:is(:has(a[href*='4%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed crimson;
}
:is(:has(a[href*='5%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed orange;
}
:is(:has(a[href*='6%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed yellow;
}
:is(:has(a[href*='7%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed green;
}
:is(:has(a[href*='8%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed blue;
}
:is(:has(a[href*='9%3F%26view_full_work%3Dtrue']) *) :has(#chapter-2) .byline {
border: 3.5px dashed navy;
}
Single-chapter fics viewed in default Contents ↑
which happens to equate, sort of, to “Entire Work”
SC berk default
I said that this is sort of the same as “Entire Work”. That's because a multichapter work will default to chapter 1 when it opens, and a single chapter work has only the one chapter (effectively the first, though yes, one could as well argue that it's also the last), and the key there is that a single chapter work still has that chapter, and that's not sophistry: although the URL reads https://archiveofourown.org/works/xxxxxxxx upon opening, it still takes the structure of https://archiveofourown.org/works/xxxxxxxx/chapters/xxxxxxxxx (though also of https://archiveofourown.org/works/xxxxxxxx?view_full_work=true, for that matter), but more about this in the SC nod view_full and SC zen /navigate sections.
This one still needed some work, and I didn't know when I'd get to it, but on Thu 17 Sep I found myself with sufficient energy and bug-up-my-ass to fix it. It used to be fine on its own, but something somewhere went a little kaka (thank you, Al, of Quantum Leap, TV, 1989). Now it's fixed.
Also: you remember how the one above isn't quite the same in work skin structure as it is in site skin structure, and you had to see the REM note? Yup, same again here.
.NOTE_re_SINGLE_chapter_works_Planescape_BERK ################################ {
content: " /// *
This set is to give a single boring border and individual muted background colors when a single-chapter work has no chapter ID, due to having surfed into it in the usual way, and reading the fic at the as-is URL.
Note that it is robust against fics that have draft chapters, which qualify that fic as multichapter even if the draft is the second chapter and no third chapter exists.
It would be, however, weak against any such two-chapter fic in which that second chapter is a draft (or any multi-chapter work in which all but chapter 1 are draft-classed), except your own work.
I did NOT get around to testing rules to identify when a fic has a draft chapter in it, but such rules would need to look for .div.chapter.draft and/or p.draft-chapter.notice and then hope that no smartass HTML Tryhard author decided to use exactly such items on their own (outside of making a work that has a draft chapter in it, I mean).
You can see examples of draft chapters not being part of the rendered DOM if you RIGHT-CLICK a given work and select View Page Source from the dropdown menu (or type viewsource: at the beginning of its URL, if you are on a phone), if it has any draft chapter(s), and note the gap in chapter continuity. Two such examples would be chapter 4 of my own work Inside, Outside, Upside-down at https://archiveofourown.org/works/64089790/chapters/164435695 (VOLUME WARNING, depending upon your browser and settings [see headnotes of chapter 1]), and chapter 9 of √test√ / Who am I, at https://archiveofourown.org/works/41832636 by TrueMaybeFalse.
If your own work has a draft chapter-2, then this rule will still apply while you are logged in (key point, since you might put this skin into Stylus or something, and so enjoy the site skin effects while still a guest reader) and will affect your work. It just will not affect such works by anyone else because the draft class will keep that chapter out of your view of the page source.
For example, the href that looks for a 0 ending to the work affects any single-chapter work whose work slug ends in 0, while the href that looks for a 1 ending to the work does the same for any work slug that end in 1. This is because there is no chapter slug, and so what would be the work directory in a multi-chapter work is now the URL slug for a single-chapter work.
For these, in testing I originally took the average of the websafe colors of the first rule set (for solid borders) and averaged their hex values with #ccc at the first random online averaging place that I found from a simple Google of https://www.google.com/search?q=average+two+hex+colors which happened to be https://meyerweb.com/eric/tools/color-blend/ and did the same again for the neon-ccc average on the borders. Here they are only #ccc, but in my test set they were [no LightGrey in any failed test this time] #666, #AA6666, #D47084, #E6B966, #E6E666, #66A666, #6666E6, #6666A6, #A666A6, and #9980B3, in case you happen to wonder.
What is below is for SITE SKINS: body:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary.
For WORK SKINS, you need a distinctly different structure: EITHER #workskin:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(.title a[href*='chapters'])) .summary OR #workskin:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(.title a[href*='chapters'])) .summary, deleting the whole :not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter) right before the end.
* ///";
}
:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted black;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='1']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted maroon;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='2']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted crimson;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='3']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted orange;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='4']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted yellow;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='5']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted green;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='6']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary{
border: 3.5px dotted blue;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='7']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted navy;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='8']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted purple;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='9']) *):not(:has(li.chapter.entire)):not(:has(li.chapter.bychapter)) .summary {
border: 3.5px dotted RebeccaPurple;
background: #ccc;
}
.NOTE_re_BORKED_attempts ################################ {
content: " /// *
These outline where I went wrong — see if you spot the PAINFUL portion of copypasta that I missed during my original runthroughs, where I failed to go through a given copy at some point of pasting, left it as-is and edited on the part that I was focused on, leaving the crucial correction to completely miss the point.
You'll find a couple of variations from my experimental notes marked asa[href$='5']simply because that's the section that I chose for testing.
* ///";
}
#workskin:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) {
border: 3.5px dotted grey;
background: #ccc;
}
.NOTE_re_SINGLE_chapter_works_Planescape_BERK_issues ################################ {
content: " /// *
When all rule subsets for {multichapter default, multichapter ?view_full_work=true, single chapter default, single chapter ?view_full_work=true, and single chapter /navigate} are together, things start breaking.
Gonna try individual rule sets alone and see if they all work on their own, then add bit by bit and move around to see if it's a conflict between them, or perhaps merely a priority between them.
* ///";
}
:is(:has(ul.user.navigation.actions li a[href$='5']) *):not(ul.user.navigation.actions li a[href*='%2Fchapters%2F']):not(:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *)) #workskin {
border: 3.5px dotted grey;
background: #ccc;
}
body:is(:has(ul.user.navigation.actions li a[href$='5']) *):not(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):not(:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_SC_BERK {
border: 5px solid green;
}
.NOTE_re_SINGLE_chapter_works_Planescape_BERK_experiments ################################ {
content: " /// *
The original format seemed OK with #workskin starting the rule, and the two tests above without #workskin starting it and instead diving straight into :is or starting instead with body: were also OK.
The alternative approach below, that HAPPENS to start with body:, was a FAIL — do NOT use the version directly below as-is.
* ///";
}
body:not(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):not(:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *) #workskin_WORKS_OK_FOR_BERK_SPOT_CHECK_BUT_NEEDS_WORK_NUMBER {
border: 3.5px dotted grey;
background: #66A666;
}
.NOTE_re_BORK-epiphany ################################ {
content: " /// *
That was when I laid out several attempts, old and new, and paid attention carefully, asking why it kept affecting the multichapter default view and the view that you get with /works removed — the https://archiveofourown.org/chapters/xxxxxxxxx view.
* ///";
}
#workskin:is(:has(ul.user.navigation.actions li a[href$='9']) *):not(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) {
border: 3.5px dotted grey;
background: #ccc;
}
body:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(ul.user.navigation.actions li a[href*="view_full_work"])):not(:has(#chapter-2)) #workskin .summary.module {
border: 3.5px dotted grey;
background: #ccc;
}
body:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(ul.user.navigation.actions li a[href*="view_full_work"])):not(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) #workskin .summary.module {
border: 3.5px dotted grey;
background: #ccc;
}
:has(ul.user.navigation.actions li a[href$='0']):not(:has(ul.user.navigation.actions li a[href*="view_full_work"])):not(:has(#chapter-2)) .summary.module {
border: 3.5px dotted grey;
background: #ccc;
}
:has(ul.user.navigation.actions li a[href$='0']):not(:has(ul.user.navigation.actions li.chapter.entire)):not(:has(ul.user.navigation.actions li.chapter.bychapter)) .summary.module {
border: 3.5px dotted grey;
background: #ccc;
}
:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(ul.user.navigation.actions li.chapter.entire)):not(:has(ul.user.navigation.actions li.chapter.bychapter)) .summary.module {
border: 3.5px dotted grey;
background: #ccc;
}
body:is(:has(ul.user.navigation.actions li a[href$='0']) *):not(:has(ul.user.navigation.actions li.chapter.entire)):not(:has(ul.user.navigation.actions li.chapter.bychapter)) .summary.module {
border: 3.5px dotted grey;
background: #ccc;
}
Single-chapter fics viewed in “Entire Work” mode Contents ↑
(explicit to the query parameter ?view_full_work=true appended to the URL)
This one has a drawback: in a single chapter work, even when viewed as https://archiveofourown.org/works/xxxxxxxx?view_full_work=true, the only place that this happens is in <ul class="work navigation actions">'s <li class="comments" id="show_comments_link_top"> and <li class="style"> (if they have a work skin applied), and in <div id="feedback" class="feedback"><ul class="actions">[...] <li id="show_comments_link><a data-remote="true" href="/comments/show_comments?view_full_work=true&work_id=24385645">Comments ([some number here]<a></li>, which isn't gonna happen if the author has comments turned off (unless, maybe, they do have some old comments even with commenting itself currently turned off, but I'm not going to search for these just to test this conjecture).
Another where it matters very much whether you are doing a site skin or a work skin: the stuff below is for site skins, but you'll never believe the insane hoops that I jumped through trying to get it to function for a work skin; so many combinations variations, even a few permutation, hell (out of sheer frustration) I did some that should absolutely not function but figured why not (given some of the contrary results of other rules kicking up results where they shouldn't have), but then I saw it, and now you will to — for a work skin, you need to use #workskin:is(:has(ul.user.navigation.actions li a[href$='6%3F%26view_full_work-true']) *) .notes... that hyphen is the big difference between this view and the view that all other view-versions use... one single, stinking hyphen instead of %3Dtrue, oy gavalt.
SC nod view_full
.NOTE_re_SINGLE_chapter_in_ENTIRE_WORK_view_NOD ################################ {
content: " /// *
This set is to give individual background colors to the last number of a WORK ID for SINGLE-chapter works ending with 5, in ENTIRE work view.
For example, the href that looks for a 0%3F%26view_full_work%3Dtrue ending to the work affects any single-chapter work whose work slug ends in 0, while 1%3F%26view_full_work%3Dtrue does the same for any work slug that end in 1. This is because there is no chapter slug, and so what would be the work directory in a multi-chapter work is now the URL slug for a single-chapter work.
* ///";
}
body:is(:has(ul.user.navigation.actions li a[href$='0%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: yellow; }
body:is(:has(ul.user.navigation.actions li a[href$='1%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: green;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='2%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: blue;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='3%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: navy;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='4%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: purple;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='5%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: RebeccaPurple;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='6%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: black;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='7%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: maroon;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='8%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: crimson;
color: white;
}
body:is(:has(ul.user.navigation.actions li a[href$='9%3F%26view_full_work%3Dtrue']) *):not(:has(ul.work.navigation.actions li.chapter.bychapter)) .notes.module {
background: orange; }
.NOTE_re_SINGLE_chapter_in_ENTIRE_WORK_view_NOD-borked version ################ {
content: " /// *
This is how I had originally arranged it. It worked for the single chapter full view mode, but unfortunately failed to exclude multchapters works' full view mode.
* ///";
}
#workskin:is(:has(ul.user.navigation.actions li a[href$='0%3F%26view_full_work%3Dtrue']) *):not(#chapter-2)_DO_NOT_USE_THIS_ONE {
background: LightGreen;
}
Single-chapter fics viewed in “Chapter by Chapter” mode Contents ↑
i.e.: single chapter at a time mode (as indicated by the URL having a /chapters/xxxxxxxxx subdirectory that immediately follows either the /works/xxxxxxxx subdirectories, or [deleting those] the URL hostname)
This is the magical /navigate thing that I keep alluding to. It works for multichapter works, as the name might imply, but also for single-chapter works, which might be a little unexpected.
Sound funky? Here's a freeby: https://archiveofourown.org/works/92529116/navigate is this current tutorial's /navigate URL; go ahead and click it and see where it brings you — and once there, click the one and only chapter that's listed (with its last-edited date, though that won't reflect edits of the work skin) on that page and you'll find yourself transported to this very tutorial's single-chapter's chapter mode of reading instead of the default view at https://archiveofourown.org/works/92529116/chapters/246666666.
Congratulations: you have now entered the Zen.
Below is the site skin subset of rules. I'm still working on cleaning up the work skin side of the house.
NB: What happens when loading single-chapter works (or multi-chapter, for that matter), but removing the /works/xxxxxxxx portion of the URL? Then you get whatever effects your work/site skin causes for chapters (since your browser will see the presence of the chapter in the page), but not the work-based effects (because that aspect of the URL isn't present in the page anymore).
SC zen /navigate
.NOTE_re_SINGLE_chapter_works_NAVIGATE_ZEN ################################ {
content: " /// *
This set is to give individual background colors to the last number of a CHAPTER ID of a one-chapter work, when having navigated to the chapter page.
For example, the href that looks for a 0 ending to the work affects any single-chapter work whose chapter slug ends in 0, while the href that looks for a 1 ending to the work does the same for any work slug that end in 1... as long as there are no other chapters in the fic.
I cycled the colors another 2 increments, but also swapped the green and yellow because the specific works that I was testing in happened to be https://archiveofourown.org/works/27330109/chapters/66774238, where the 9 and 8 were perfectly OK, and https://archiveofourown.org/works/24385645/chapters/58817800, in which the 5 was OK, but the 0 caused a problem of the green border here blending with the MULTI_in_simple_singleton rule li a[href*='5%2Fchapters'] background green.
PAY ATTENTION TO YOUR OTHER RULE DECLARATIONS when you make a new rule declaration! 😑
* ///";
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='0']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted yellow;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='1']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted blue;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='2']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted navy;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='3']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted purple;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='4']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted RebeccaPurple;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='5']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted black;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='6']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted maroon;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='7']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted crimson;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='8']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted orange;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='9']):has(a[href*='to=%2Fworks%2F']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted green;
}
.NOTE_re_SINGLE_chapter_works_NAVIGATE_ZEN-borked-tests ################################ {
content: " /// *
These are what I used near the end.
In the first two cases, the absence of chapter-2 was to determine that this is a single-chapter work whose chapter URL has been reached through navigation to its specific chapter URL, but it failed — I went a different route, but maybe you would prefer to chase this version for one reason or another.
The third one, aside from swapping to a border because why not — and because I realized that I was already using background on view_full_work... ahem — did identify https://archiveofourown.org/works/xxxxxxxx/chapters/xxxxxxxxx, but also falsely identified multichapter in default, as you might expect — though this was an improvement. Not so good was that it also falsely identified multi- and single-chapter works of the form https://archiveofourown.org/chapters/xxxxxxxxx, though I think that this is probably not something that most people would be concerned over.
The fourth was really close, properly identifying the single chapter works https://archiveofourown.org/works/xxxxxxxx/chapters/xxxxxxxxx while falsely identifying only the single (not the multi) chapter versions of that URL format.
After that, I fixed it and you have what you see above as the final product. I changed the first rule declaration from green to yellow, due to the border blending into the background... which I had been trying to avoid the risk of, but sometimes it happens anyway... and I spent a little while scratching my head before tumbling to the problem there.
* ///";
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='0']):not(#chapter-2) #workskin_FAILS_ENTIRELY {
background: aqua;
}
body:has(ul.user.navigation.actions li a[href*="/chapters/"]):has(ul.user.navigation.actions li a[href$='0']):not(:has(#chapter-2)) #workskin div.preface.group_FAILS_ENTIRELY {
background: aqua;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='0']):not(#chapter-2) .notes.module_DOES_ID_the_right_one-but-also-false-IDs-others {
border: 3.5px dotted green;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='0']):not(:has(ul.work.navigation.actions li.chapter.entire)) .notes.module {
border: 3.5px dotted green;
}
— — —
NB re. SC zen /navigate experiments
:is(:has(a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='Insert_Glyph_{0...9}_Here']):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin {
and
:has(ul.user.navigation.actions li a[href$='Insert_Glyph_{0...9}_Here']):is(:has(a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin {
are alternatives to experiment with.
Timestamps Contents ↑
...the final frontier (last-edit's UNIX date)
.expandable updated_at
Below is the site skin subset of rules. I need to work on the work skin version.
For the initial glyph (mostly useless, unless you don't mind a lot of 1s, or are willing to style 90 rules for 1x [initial value of 10 through 99] or 900 rules for 1xx [initial value of 100 through 999]):
:has(li.download ul.expandable.secondary a[href*='updated_at=ONE_THROUGH_NINE']) #workskin {
because the UNIX date is never going to begin with a zero, just like a normal calendar year won't either. This one gets only 9 rules, not 10.
For the final glyph (much more evenly distributed values):
:has(li.download ul.expandable.secondary a[href$='ZERO_THROUGH_NINE']) #workskin {
because the UNIX date most certainly can end with a zero, just like a normal calendar year can. This one gets the usual 10 rules.
:has(li.download ul.expandable.secondary a[href$='0']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='1']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='2']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='3']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='4']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='5']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='6']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='7']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='8']) #workskin {
border: 5px solid grey;
}
:has(li.download ul.expandable.secondary a[href$='9']) #workskin {
border: 5px solid grey;
}
— — —
Thought process leading to that
This is where you might have scratched your heads, so here are my original notes (edited a little bit in order to try to make a little more intelligible, since notes-to-self are often shorthanded into nigh-on replacement codes):
Examples of the relevant HTML follow (taken from the rendered DOM via DevTools [hence after AO3 runs its JS], rather than the unreliable page source [that comes before AO3's routines run the site’s JS]) in the default collapsed-list state of the button:
<li class="download">
<noscript>
<h4 class="heading">Download</h4>
</noscript>
<button class="collapsed" fdprocessedid="z0hu7r">
Download
</button>
<ul class="expandable secondary hidden">
<li>
<a href="/downloads/84197351/Olive_Pine_Moon_site.azw3?updated_at=1778083158">AZW3</a>
</li>
<li>
<a href="/downloads/84197351/Olive_Pine_Moon_site.epub?updated_at=1778083158">EPUB</a>
</li>
<li>
<a href="/downloads/84197351/Olive_Pine_Moon_site.mobi?updated_at=1778083158">MOBI</a>
</li>
<li>
<a href="/downloads/84197351/Olive_Pine_Moon_site.pdf?updated_at=1778083158">PDF</a>
</li>
<li>
<a href="/downloads/84197351/Olive_Pine_Moon_site.html?updated_at=1778083158">HTML</a>
</li>
</ul>
</li>
(and then in the button’s expanded form, presenting the reader with formats in which to download the example work, the only differences are <button class="expanded" ... <ul class="expandable secondary"> [where this latter is notably missing the hidden class, for obvious reasons]) from which I surmised that #workskin:is(html:has(> body > li.download ul.expandable.secondary a[href*='updated_at=0'])) { or #workskin:is(html:has(> body > li.download ul.expandable.secondary a[href$='0'])) { could be the right structure to properly target the relevant glyphs and [due to a set of ten similar rules each, for all glyphs {1...9} for the initial glyph of the timestamp and a second set of ten rules of all glyphs {0...9} for the final glyph of the timestamp] enact a given declaration (background color, for example) — in this work’s particular case it happens to be 1 and 8, but while the 1 will remain true for quite some time to come, the 8 is quite volatile and stands ~1/10 chance of being any given numeral per random time edit (if any are made... such as applying a different site skin).
If a work is edited, then the timestamp of its last edit will change to reflect that UNIX date, but will remain that same date until the work is ever again edited.
It was fiddly, but after a day or so I found that
#workskin:is(html:has(a[href*="updated_at=1"]) *) {
background: #ddd;
}
and
#workskin:is(html:has(body li.download a[href*="updated_at=1"]) *) {
background: #dcb;
}
seemed like decent directions.
Further testing showed that
#workskin:is(html:has(body li.download a[href$="0"]) *) {
border: 1px solid black;
}
(and nine similar rules for $={1...9} with nine other colors to be certain that the condition enacts the relevant condition) also worked.
I swapped to #workskin:is(html:has(body li.download a[href$="0"]) #workskin) { in order to ensure greater clarity when editing the CSS (obviously target whichever element one wishes within the work, rather than affecting necessarily the entire #workskin area).
#workskin:is(html:has(a[href*="updated_at=1"]) *) { and #workskin:is(html:has(body li.download a[href*="updated_at=1"]) *) { work fine, but I’d suggest the latter since I can’t say that the former will never appear in some other part of the page (if nothing else, then potentially someone could drop [in a work or a comment] a d/l link with a timestamp in it, unnecessarily).
div.work ul.work.navigation.actions li.download ul.expandable.secondary a[href is hardly likely to be accidentally used... but I know several people who might emulate an entire AO3 work page, so with work skins’ use of id= having been nuked back in June 2025, #show_comments_link_top ~ a[href is arguably best practice (as long as the reader doesn’t use a script to move the download button to anywhere before the Comments button or cause it to be other than a subsequent sibling in any other way).
TIMESTAMP FIRST NUMBER = :has(li.download ul.expandable.secondary a[href*='updated_at=160_THROUGH_169']) #workskin {
NB: I had originally written 16_AND_ZERO_THROUGH_NINE in order to support a healthy distro of 3-third value from 13 Sep 2020 through 14 Nov 2023, and the principle still stands, but in re-reading that, it left me confused until I caught my note-to-self here.
Just take it as read that the 160-through-169 in this case is just a starting point (though a good one: at 1,6Xy,yyy,yyy that’s 10M y-set permutations per single X-glyph, and people will update at random — but of the /works/84197351 work number value as of 10:00 CDT 03 May, and with [current] values skipping four to enumerate works every fifth –xxx1 and –xxx6 final glyph, let’s posit that they’ve always enumerated thus [just for a ballpark framework here], and surmise that there might be on the order of 8.4M total works and hence ~8.4M $=Y, setting aside how many might no longer exist due to deletion), though going back to {/works/4197363 through ...66} being a 2-value-skip and {/works/67400341 through ...45} being a 3-value-skip shows that the skip-range has varied over time, so the actual value is likely distinctly more than 8.4M. Due to this, I can’t say from spot-checks how much is from deleted works and how much (if any) is from work number skipping when new works are assigned a value.
That ignores all other non 16x values, and would need 7x (1992), 8x, ..., 15x, 16x to be even half-OK, and would need a default fallback to cover everything dated outside of that range.
I prefer the $=Y, since that will cycle far more smoothly and equally distributed, over entropic background.
TIMESTAMP LAST NUMBER =:has(li.download ul.expandable.secondary a[href$='ZERO_THROUGH_NINE']) #workskin {
A few of the tests along the way Contents ↑
Testing: 1, 2, 3.5, -7, i*e^π, blue, Abraham Lincoln, ...
These are old tests from along the way, as explained in the opening REM note. Keep the note in your copypasta, if you happen to grab this subset, simply because having a bunch of rules without some explanation for them royally sucks. ...ask me how I know 😑....
.NOTE_re_TESTS ################################ {
content: " /// *
These were only some tests along the way. There were a hell of a lot of typos, red herrings, and so forth (don't ask about the agita of is:(has: having to come before not:), and I didn't keep all of the fails in my records while homing in on functional versions (and probably some of the following have extra material that was later whittled down), but since I do have some still in my testing skins, I figured that I'd share them for the curious.
Some of them worked fine on their own, but conflicted with some other rule(s), or were insufficiently precise (affecting too broad a category, like checking to see if there's a work ID as a preliminary test without yet checking for the ID ending in some specific value, for example).
I include the fails because they can be of value in showing exact fails that might work with a tweak, or they might spark some completely different insight for you.
These are not intended for use in your skin as such, unless you want to build upon these in a different direction. They're here only as a record of some of the things that I tried, for your reference.
* ///";
}
.NOTE_re_EARLY_stuff ################################ {
content: " /// *
First you have the _very_ early stuff from some .txts and eventually a spreadsheet once I got tired of the Notepad mess, before I moved on to annotating in the test skins themselves. Putting these first might help give some sense of how and why the material evolved.
* ///";
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='%2Fworks%2F']) *):has(ul.user.navigation.actions li a[href$='5']):not(ul.user.navigation.actions li a[href*='%2Fchapters%2F'])_TXT_REM_NOTE-says-it-functions-for-SINGLE-chapter-works-ending_with_5_obviously-in-DEFAULT-mode {
background: yellow;
color: black;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='1%2Fchapters%2F']) *)_TXT_REM_NOTE-says-it-functions-for-MULTI-chapter-works-ending_with_1_obviously-in-default-mode-but-you-can-see-that-it-is-not-exclusive-of-others {
background: pink;
color: black;
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='1%3F%26view_full_work%3Dtrue']) *)_TXT_REM_NOTE-says-it-functions-for-MULTI-chapter-works-ending_with_1_obviously-in-ENTIRE-mode {
background: orange;
color: black;
}
#workskin:is(:has(li a[href$='5%3F%26view_full_work%3Dtrue']) *):not(li a[href*='id="chapter-2"'])_TXT_REM_NOTE-says-it-functions-for-SINGLE-chapter-works-ending_with_5_obviously-in-ENTIRE-mode-_BUT-that-makes-no-sense-if-a-multi-chapter-has-a-chapter-2-in-DRAFT-form {
background: lavender;
color: black;
}
#workskin:is(:has(li a[href*='5%3F%26view_full_work%3Dtrue']) *):not(li a[href*='%2Fchapters%2F'])_TXT_REM_NOTE-says-it-functions-for-SINGLE-chapter-works-ending_with_5_obviously-in-ENTIRE-mode-and-says-NOT_NEEDED_IF_DIFFERENTIATING_FOR_CHAPTER_FINAL_URL_NUMBER {
background: LightGreen;
color: black;
}
#workskin:is(:has(li a[href*='%2Fchapters%2F']) *):not(li a[href*='id="chapter-2"'])_TXT_REM_NOTE-says-it-functions-for-SINGLE-chapter-works-ending_with_5_obviously-in-NAVIGATE-chapter-mode {
background: aqua;
color: black;
}
.NOTE_re_FIRST_TEST_skin ################################ {
content: " /// *
These are rules that show up in my .txt of the first site skin test (and might have conflicted with some other rule(s) or been too broadly or too narrowly focused), but which are neither present in the early notes nor in my current test skins.
* ///";
}
#workskin:is(:has(ul.user.navigation.actions li a[href*='0%3F%26view_full_work%3Dtrue']) *)_was-for-MULTI_in_doom_scroll_mode {
border: 3.5px dashed black;
}
:is(:has(li a[href*='%2Fchapters%2F']) *):has(li a[href$='0']):not(li a[href*='id="chapter-2"']) #workskin_was-for-SINGLE_chapter_works_NAVIGATE_ZEN_mode {
background: aqua;
}
.NOTE_re_SECOND_TEST_skin ################################ {
content: " /// *
These are rules that show up in my .txt of the second site skin test (and might have conflicted with some other rule(s) or been too broadly or too narrowly focused), but which are neither present in the early notes, nor my prior test skin .txt, nor in my current test skins.
* ///";
}
:is(:has(li a[href*='%2Fchapters%2F']) *):has(li a[href$='2']):not(li a[href*='id="chapter-2"']) #workskin_was-for-SINGLE_chapter_works_NAVIGATE_ZEN_mode {
background: aqua;
}
.NOTE_re_THIRD_TEST_skin ################################ {
content: " /// *
These are rules that show up in my .txt of the third site skin test (and might have conflicted with some other rule(s) or been too broadly or too narrowly focused), but which are neither present in the early notes, nor my prior test skin .txts, nor in my current test skins.
The purpose of the third test skin was to sort out what I already had and select unique identifiers (whether standalone, preferably, or in pairs or larger subsets) to single out only each mode of reading, rather than falsely identify any further modes.
* ///";
}
:has(ul#chapter_index) #workskin_was-for-MULTI_in_simple_singleton_view-but-clearly-is-only-a-snippet-sufficient-to-look-for-the-presence-of-chapter-indices {
border: 2px solid black;
}
:has(li.chapter.bychapter) #workskin_was-for-MULTI_in_doom_scroll_mode-but-clearly-is-only-a-snippet-sufficient-to-look-for-the-presence-of-the-chapter-li {
border: 3.5px dashed red;
}
:is(:has(a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_was-for-SINGLE_chapter_works_NAVIGATE_ZEN {
background: aqua;
}
.NOTE_re_INCOMPLETE_rule ################ {
content: " /// *
These two rules HERE in this note (NOT the next two below this note) showed up as-is, sans declaration.
Much like the two that show up later in the .NOTE_re_RECENT_testing_skins section below (cf. -to-try-to-see-different-PREV-value-in-each-chapter and -to-try-to-see-different-NEXT-value-in-each-chapter), these two had a note in the .txt that read 'try finding that prev and next exist, but ignore their values and look for current a[href]'.
body:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters']) *):has(ul#chapter_index):has(li.chapter.previous):has((ul.user.navigation.actions li a[href$='6']) *) #workskin,
body:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters']) *):has(ul#chapter_index):has(li.chapter.next):has((ul.user.navigation.actions li a[href$='6']) *) #workskin
but there was no indication of how they fared, beyond stating 'OK, this is getting insane'.
Just a thought, but one could likewise identify single chapter works by the ABSENCE of next/previous chapter buttons using :not(:has, though it would mean covering both li.chapter.next and li.chapter.previous.
More insane, however, is a note-to-self in the third page of my spreadsheet. for a multi-chapter work in single-chapter mode (the default view), I was considering drilling down into ul#chapter_index.expandable.secondary + li + form action=''/works/75014351/chapters/196008231 + p + select name=''selected_id'' id=''selected_id'' + option selected=''selected'' value=''196008231'' + option value=''197078581'' + span.submit.actions + input type=''submit'' name=''commit'' value=''Go'' + li + a href=''/works/75014351/navigate'' (sorry for all of the doubled apostrophes, but I needed to indicate where the quotation marks were without using quotation marks or else it would break the CSS were you to copy this to a skin).
* ///";
}
.NOTE_re_RECENT_testing_skins ################################ {
content: " /// *
Now we have the stuff from my RECENT test skins, as nearly chronologically ordered as I can reconstruct, though that might not matter really.
I copied these before I dug through the older material in my .txts above, so they're definitely more up-to-date than those, though NOT as up-to-date as the actual CURRENT material in the non-testing portions of this tutorial as a whole.
* ///";
}
:is(:has(a[href*='0%3F%26view_full_work']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_SC_NOD-nb-cf-other-of-this-same-rule-using-WORK_FINAL_NUMBER_%3F-instead-of-0%3F {
border: 5px solid black; }
:is(:has(ul.user.navigation.actions li a[href*='WORK_FINAL_NUMBER_%2Fchapters']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_SC_ZEN {
border: 5px solid black; }
:is(:has(a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href*='WORK_FINAL_NUMBER_%2Fchapters']):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_SC_ZEN_CORRECTED_FOR_NEEDING_TO_ID_PRESENCE_OF_CHAPTERS_EVEN_THOUGH_THAT_SHOULD_BE_IMPLICIT_TO_THE_WORK_NUMBER_CONDITION {
border: 5px solid black; }
:is(:has(ul.user.navigation.actions li a[href*='WORK_FINAL_NUMBER_%2Fchapters'])):is(:has(a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_SWAPPED_FIRST_AND_SECOND_CONDITIONS_OF_SC_ZEN_---WORK---_NUMBER_GOOD_IT_WORKS_FOR_SC_ZEN_AND_YES_THE_SECOND_IS_IS_REQUIRED {
background: black; }
:is(:has(ul.user.navigation.actions li a[href*='CHAPTER_FINAL_NUMBER_%2Fchapters']) *):has(ul#chapter_index) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_BG_PER_MC_CH_VIEW_CH_NUMBER-was-test-of-MULTI_in_simple_singleton_view {
background: black; }
:is(:has(a[href*='WORK_FINAL_NUMBER_%3F%26view_full_work']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_BG_PER_SC_NOD_CH_NUMBER-nb-cf-other-of-this-same-rule-using-0%3F-instead-of-WORK_FINAL_NUMBER_%3F {
background: black; }
:has(li.download ul.expandable.secondary a[href*='updated_at=ZERO_THROUGH_NINE']) #workskin_THIS TESTS_GOOD_IT_WORKS_FOR_UNIX_TIMESTAMP_OF_LAST_EDIT {
border: 5px solid grey; }
:is(:has(a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='CHAPTER_FINAL_NUMBER_HERE_']):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_ORIGINAL_SC_ZEN_CHAPTER_LAYOUT {
border: 5px solid grey; }
:has(ul.user.navigation.actions li a[href$='CHAPTER_FINAL_NUMBER_HERE_']):is(:has(a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_SWAPPED_SC_ZEN_CHAPTER_LAYOUT_FOR_TESTING {
border: 5px solid grey; }
:has(ul.user.navigation.actions li a[href*='0%2Fchapters']):is(:has(a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin {
background: black;
}
:is(:has(ul.user.navigation.actions li a[href$='5']) *) #workskin_THIS TESTS_GOOD_IT_WORKS {
border: 5px solid blue;
}
body:not(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter) *):has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *) #workskin_NO_REM_NOTE_ON_THIS_ONE {
background: yellow;
border: 2px solid green;
}
body:not(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *) #workskin_YES_GOOD {
background: yellow;
border: 2px solid green;
}
body:not(:has(li.chapter.bychapter) *) #workskin_YES_GOOD {
background: yellow;
border: 2px solid green;
}
body:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *) #workskin_FAIL-for-SC-in-default-Berk {
background: yellow;
border: 2px solid green;
}
:has(body[data-view-full-work="true"]) #workskin_FAIL {
background: yellow;
border: 2px solid green;
}
is(:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *)) #workskin_FAIL {
background: yellow;
border: 2px solid green;
}
is(:has(body #header ul.user.navigation.actions li a[href*='view_full_work']) *)) #workskin_FAIL {
background: yellow;
border: 2px solid green;
}
is(:has(a[href*='view_full_work']) *))_FAIL-for-SC-in-default-Berk {
background: yellow;
border: 2px solid green;
}
:is(body.javascript *) :is(:has(a[href*='view_full_work']) *))_FAIL {
background: yellow;
border: 2px solid green;
}
body:not(:has(a[href*='view_full_work']) *) #workskin_BERK_and_ZEN {
background: yellow;
border: 2px solid green;
}
:not(:has(a[href*='view_full_work']) *) #workskin_ALL_SCREENS {
background: yellow;
border: 2px solid green;
}
:not(:not(:has(a[href*='view_full_work']) *)) #workskin_MC_ALL_and_NOD {
background: yellow;
border: 2px solid green;
}
:not(:not(:has(a[href*='view_full_work']) *)):not(:has(li.chapter.bychapter)) #workskin_MC_SINGLE_and_NOD {
background: yellow;
border: 2px solid green;
}
:not(:not(:has(a[href*='view_full_work']) *)):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_GOOD_YES_WORKS_ONLY_IN_NOD {
background: yellow;
border: 2px solid green;
}
:not(:not(:has(a[href*='view_full_work']) *)):not(:has(li.chapter.bychapter)):not(:has(ul#chapter_index)) #workskin_GOOD_YES_WORKS_ONLY_IN_NOD {
background: yellow;
border: 2px solid green;
}
:is(:has(a[href*='view_full_work']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_GOOD_YES_WORKS_ONLY_IN_NOD-nb-Can-use-ul#chapter_index-instead-and-can-open-with-:not(:not {
background: yellow;
border: 2px solid green;
}
:is(:has(a[href*='view_full_work']) *):not(:has(li.chapter.bychapter)):not(:has(ul#chapter_index)) #workskin_GOOD_YES_WORKS_ONLY_IN_NOD {
background: yellow;
border: 2px solid green;
}
body:(has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):not(:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *):not(:has(ul#chapter_index)) #workskin_FAIL {
background: yellow;
border: 2px solid green;
}
body:(has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):not(:has(ul.user.navigation.actions li a[href*='view_full_work']) *):not(:has(ul#chapter_index)) #workskin_FAIL {
background: yellow;
border: 2px solid green;
}
:is(:has(li a[href*='%2Fchapters%2F']) *):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin_GOOD_YES_WORKS_ONLY_IN_ZEN {
background: yellow;
border: 2px solid green;
}
:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters%2F']) *):not(:has(ul.user.navigation.actions li.chapter.bychapter)):not(:has(ul.user.navigation.actions li.chapter.entire)) #workskin_MC_singles_and_ZEN {
background: yellow;
border: 2px solid green;
}
body:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters']) *):has(ul#chapter_index):has(ul.work.navigation.actions li.chapter.previous a[href$='1#workskin']) #workskin_TESTING_OFF-did-not-leave-note-of-results-but-was-test-of-MULTI-CHAPTER-WORK-CHAPTER-number-stuff-to-try-to-see-different-PREV-value-in-each-chapter-CF-NOTE_re_INCOMPLETE_rule,
body:is(:has(ul.user.navigation.actions li a[href*='%2Fchapters']) *):has(ul#chapter_index):has(ul.work.navigation.actions li.chapter.next a[href$='1#workskin']) #workskin_TESTING_OFF-did-not-leave-note-of-results-but-was-test-of-MULTI-CHAPTER-WORK-CHAPTER-number-stuff-to-try-to-see-different-NEXT-value-in-each-chapter-CF-NOTE_re_INCOMPLETE_rule {
border: 2px double green;
background: black;
color: white;
}
:is(:has(ul.user.navigation.actions li a[href*='0%3F%26view_full_work%3Dtrue']) *):has(li.chapter.bychapter) #workskin-did-not-leave-note-of-results-but-was-test-of-MULTI_in_doom_scroll_mode {
border: 3.5px dashed #666;
}
body:not(:has(ul.user.navigation.actions li a[href*='0%2Fchapters%2F']) *):not(:has(ul.user.navigation.actions li a[href*='%3F%26view_full_work%3Dtrue']) *) #workskin-did-not-leave-note-of-results-but-was-test-of-SINGLE_chapter_works_Planescape_BERK {
border: 3.5px solid grey;
background: #ccc;
}
:is(:has(a[href*='%2Fchapters%2F']) *):has(ul.user.navigation.actions li a[href$='0']):not(:has(li.chapter.bychapter)):not(:has(li.chapter.entire)) #workskin-did-not-leave-note-of-results-but-was-test-of-SINGLE_chapter_works_NAVIGATE_ZEN {
border: 0.18em ridged grey;
background: aqua;
}
Further considerations Contents ↑
I'm not gonna add special effects logic to detect fics being part of one particular collection or another, though I could. It might be fun for a general %2Fcollections%2F effect when viewed as part of a collection (by which I don't mean for the site/work skin to simply check to see if a work happens to be part of <a href="/collections/CSS_Abuse">CSS Abuse and HTML Tryhard</a>, for example — though that would be something that one might want in a site skin, at least — but rather that the site/work skin should look to see if the current URL contains that collection's subdirectory in it, such as via :has(a[href*='/users/logout?return_to=%2Fcollections%2FCSS_Abuse']) #workskin {, for example).
That is: the effect wouldn't be visible in the fic's blurb while in the collection itself and just scrolling down the list of works in it, but when one is in a collection and clicks into a work there, the work's URL then becomes .https://archiveofourown.org/collections/CSS_Abuse/works/xxxxxxxx for example
...or so I thought. By “think”, I mean “know damned well and had the above two paragraphs in my notes because I had been looking at the issue directly rather than imagining some hypothetical”, but that seems to have changed. I would say that maybe I'm just tripping, but that's like passing by a coffee shop every day for six years without ever going in, and then when you finally get a craving for coffee and a doughnut, you find yourself scratching your head over the fact that there's a pizzeria where you could swear there had been a coffee shop. But hey: I don't have screenshots of it, so... pics or it didn't happen, right? (Though, of course: such wouldn't prove a thing, strictly, since they would be a breeze to create with a spoofed page, or anyone might Photoshop or these days optical-LLM something into existence.)
So if it isn't the case, and maybe had been / maybe never had been, then why am I keeping this pointless-seeming note? Simple: it's an object lesson. Doesn't matter whether that had been the case in the past or I've been Mandected, the fact remains that things do change here on AO3 (the rendered DOM can suddenly be officially restructured, some CSS property can suddenly cease operating properly by removal from the whitelist or by some weird interaction with an unrelated change, etc.). What currently works or fails outright in this or any other tutorial (mine or anyone else's) might no longer be true tomorrow (or next week, or next month, or next year, or a decade from now); some workaround might puzzle you in someone's fic (maybe redundant tags, or some bizarrely configured HTML/CSS under their hood), and all because something changed between their writing it and your reading it (new tags canonized, merged, parented, or what have you; new HTML/CSS suddenly permitted or [rarely] prohibited).
I'm glad that I didn't waste my time building the rules for checking the source for being viewed from within a collection, since had I done so you would now be looking at them, looking at this tutorial's URL (if you got to it through a collection, rather than a tag or my Dashboard page, or however else), looking back and forth a couple more times, and concluding that I must've accidentally dream-typed this section (bringing to mind the phrase “I don't know what drugs you're on, man, but you need to either get off of them or up the dose.”).
...or so it seemed. I dug a little further, and it's a coin toss:
-
First I went into my food-heavy works in Food Porn of Icewall and found that the first two works (BeRoniCorp interlude: vignettes en rose and Ruru's house has many doors – or: What dreams may come) now-predictably failed to show the
/collections/Food_Porn_of_Icewallsubdirectories, - but then the third one (always check for variables: never trust one or two examples alone; and always click random bits throughout, rather than just first few or last few or a small run in the middle) — Snoopy Presents: It's a nightmare on Elm Street, Charlie Brown! — DID show the subdirectories,
-
and while in my CSS Abuse and HTML Tryhard collection and clicking into Userscript and CSS, as you prefer, to return overflow and sticky effects client-side!, the same thing again happened and that work's URL did indeed show the
/collections/CSS_Abusesubdirectories...
which is where I give up. It's not a question of when they were first uploaded-and-released or last updated (these last two varying between /navigate and UNIX date timestamp):
| Work | Uploaded | /navigate * | d/l's last-edit timestamp |
|---|---|---|---|
| BeRoniCorp | 30 Nov 2025 | 07 Dec 2025 | 18 Apr 2026 |
| Ruru | 19 Jan 2025 | 02 Feb 2025 | 21 Aug 2026 |
| Snoopy | 22 Sep 2024 | 22 Sep 2024 | 27 Aug 2026 |
| Userscript | 12 Jun 2026 | 12 Jun 2026 | 20 Jul 2026 |
* though I had to delete the collection subdirectories from the URL in order for the appended /navigate subdirectory to show the chapters' dates (instead of being presented with an error page
).
Well, whatever. I'm throwing in the towel on that one. If there's an easy workaround or predictable context to the coin toss, great, but I don't care; you're welcome to pry away at it.
— — —
On a separate note, I wonder about logged-out readers; no, they wouldn't be able to use a site skin (though they certainly might use some third party extension such as site skin-like CSS in Stylus or a userscript in Tampermonkey/Violentmonkey, or something, and so could then effectively see things using the methods in this tutorial even when logged-out), but an author using the CSS of this tutorial could still cause their work skin's intended effects without a problem (assuming that the logged-out reader weren't to turn off Creator's Style, obviously).
That raises the question of checking to see if the reader is in logged-out state. Seeing if the reader is logged-out is no problem, so one could cause an entire separate set of effects based upon the reader's logged-in/-out state, since stuff like to=%2fchapters is still in the chapter-by-chapter page source and the work ID is still in the download button list regardless of logged-in/-out state.
Mewsmodeus (Mewzebub) pioneered the check for logged-in/-out state in I'M NOT AN FANFIC AUTHOR PLEASE DON'T CURSE ME, and you can see a break-down of how to detect the reader's state (using Mewz's detect-user CSS logic) in this comment thread of my Targeting specific AO3 work sections (not site) with CSS effects tutorial.
(If you're comfortable with it, then you can simply copypaste view-source:https://archiveofourown.org/works/62524168 or view-source:https://archiveofourown.org/works/72708781/chapters/189385276 [to a new tab would be easier] and CTRL-F [search] for the REM note at #workskin .NOTE_re_USER_GREETING { [which I'm very glad to have written down there, or I'd never have gotten right all of the who-did-what]. It kind of has a complicated group effort effect there.)
Luckily, GumbaBunny also covered its execution in their 25 Jun 2026 Username Detector chapter (currently ch. 19) in the 𝗖𝗼𝗱𝗶𝗻𝗴 𝗘𝗻𝗰𝘆𝗰𝗹𝗼𝗽𝗲𝗱𝗶𝗮, which gives you an alternative walkthrough upon which to draw (different ways of explaining things are sometimes far more helpful than just one explanation).
— — —
Something that I didn't explore, partly because I got lost in the weeds of troubleshooting, partly because I forgot to with all of the troubleshooting, and partly because it's not really likely that anyone would really pursue chapter numbers in the URL without the preceding work numbers, is the question of targeting for https://archiveofourown.org/chapters/xxxxxxxxx and differentiating between those that happen to be multichapter and single chapter — I ensured only that they didn't accidentally get targeted by any other rules accidentally.
I'm leaving that as an exercise for the reader.
😉
— — —
Last item, and this bears repeating: I did NOT get around to testing rules to identify when a fic has a draft chapter in it, but such rules would need to look for .div.chapter.draft and/or p.draft-chapter.notice and then hope that no smartass HTML Tryhard author decided to use exactly such items on their own (outside of making a work that has a draft chapter in it, I mean).
I mentioned this already up in the .NOTE_re_SINGLE_chapter_works_Planescape_BERK, since there was already mention of drafts there, but it's worth mentioning here in the homework section, as it were.
O ~~~ O
