/*
 * Everything the site draws that is not the main/alt treatment itself.
 *
 * identity.css keeps its narrow contract - it is the polarity treatment and the
 * two variables the whole page reads, and it is guarded by tests that pin
 * properties of that file specifically. This file is the rest: vote controls,
 * the composer, and the small amount of chrome left over.
 *
 * The same two editing rules apply here, and they are guarded the same way:
 *
 * 1. Modifiers are written with the class doubled - `.composer__box.composer__box--alt` -
 *    so they outrank the base rule on specificity rather than on source order.
 *    Written singly, a base rule further down the file silently wins.
 * 2. No `border:` or `font:` shorthand in the base rules. The shorthand resets
 *    border-style and font-style, which are two of the redundant signals, and
 *    it does it without any warning that it has happened.
 *
 * There is no JavaScript on this site - the content security policy says
 * script-src 'none' - so anything here that behaves has to do it in CSS.
 */

/* -- tokens --------------------------------------------------------------- */

/*
 * Stage 7. Everything the redesign adds, as variables, so a later change is a
 * value rather than a sweep through rules.
 *
 * `--page-bg` and `--page-fg` are **not** here — they live in identity.css,
 * because they are the polarity the main/alt treatment inverts and that file
 * owns them. These are derived from them in spirit but stated as literals,
 * because they are not a polarity: inverting a hairline is meaningless.
 *
 * No web font is named, and none can load: the content security policy is
 * `default-src 'none'` and sets no `font-src`. These are the reader's own
 * faces. The serif is the one channel carrying most of the site's character,
 * so the stack is ordered by how good the face is rather than by ubiquity,
 * with a guaranteed fallback at the end.
 */
:root {
  --surface: #f4f0e6;
  --surface-edge: #e2dcd0;
  --rule: #e9e3d8;
  --rule-strong: #16140f;
  --ink-soft: #2a251e;
  --muted: #5a5348;
  --faint: #8a8172;
  --accent: #8c2f1b;
  --accent-soft: #f6e7e1;

  --serif: Georgia, "Iowan Old Style", "Palatino Linotype", "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --measure: 46em;
}

/*
 * Not designed for; kept contrasting. The same argument as identity.css's dark
 * branch, and for the same reason: these values sit beside a polarity that
 * inverts, and a token that stopped contrasting in dark mode would put
 * unreadable text on exactly one of the two persona treatments.
 */
@media (prefers-color-scheme: dark) {
  :root {
    --surface: #1d1a15;
    --surface-edge: #34302a;
    --rule: #2b2721;
    --rule-strong: #f2efe7;
    --ink-soft: #e6e2d9;
    --muted: #b8b1a4;
    --faint: #8a8172;
    --accent: #e08b72;
    --accent-soft: #2a1d18;
  }
}

/* -- the page ------------------------------------------------------------- */

/*
 * The body's colours are set in identity.css and must stay there. This rule
 * gives it everything else.
 */
body {
  margin: 0;
  /* So the footer sits at the bottom of a short page rather than halfway up. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
}

.page {
  box-sizing: border-box;
  flex-grow: 1;
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding: 2rem 1.5rem 4rem;
}

/*
 * The front page only. Its three secondary columns inside the ordinary
 * measure come out around fourteen ems each, which is not enough for a
 * headline to break well. Nothing else on the site is laid out in columns,
 * so nothing else wants this.
 */
.page.page--wide {
  max-width: 76rem;
}

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.2;
}

h1 {
  margin: 0 0 1.25rem;
  font-size: 2rem;
  letter-spacing: -0.015em;
}

h2 {
  font-size: 1.4rem;
}

h3 {
  font-size: 1.15rem;
}

a {
  color: var(--accent);
}

a:hover,
a:focus-visible {
  text-underline-offset: 3px;
}

/*
 * Form controls, for the pages that write plain HTML and no classes — sign in,
 * sign up, report, request a board. The composer's own fields are styled in its
 * section below and win on class specificity, so the two do not fight.
 */
/*
 * `select` is in this list so a dropdown matches the text fields beside it —
 * same size, same border, same colours. It keeps the browser's own arrow:
 * drawing one would mean a background image, and the policy is
 * `default-src 'none'` with no `img-src`, so the arrow would simply not load.
 */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="url"],
select,
textarea {
  box-sizing: border-box;
  width: 100%;
  max-width: var(--measure);
  padding: 0.5em 0.6em;
  background: var(--page-bg);
  color: inherit;
  border-width: 1px;
  border-style: solid;
  border-color: var(--surface-edge);
  border-radius: 4px;
  font-family: inherit;
  font-size: inherit;
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline-width: 2px;
  outline-style: solid;
  outline-color: var(--accent);
  outline-offset: 1px;
}

label {
  font-size: 0.9em;
  color: var(--muted);
}

button {
  padding: 0.5em 1em;
  background: var(--surface);
  color: inherit;
  border-width: 1px;
  border-style: solid;
  border-color: var(--surface-edge);
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
  font-size: inherit;
}

button:hover,
button:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}

/* -- chrome --------------------------------------------------------------- */

/*
 * The banner. It names the site and nothing else.
 *
 * **No identity appears here, in any form.** §5.6 keeps the persona signal for
 * surfaces where somebody is about to act, because chrome stops being seen
 * after a week — and since stage 4 there is no active identity for it to name
 * even if that rule went away (§1.5a). So this renders identically for both of
 * an account's identities, which is §5.1 satisfied by construction rather than
 * by a sweep.
 *
 * The signed-in half carries a form (Sign out) and therefore a CSRF token, which
 * is why it sits behind `user.is_authenticated` in the template. A token on a
 * logged-out page would make every public page `no-store` and take the whole
 * site out of the CDN (§8.3).
 */
.chrome {
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--surface-edge);
  background: var(--surface);
}

.chrome__bar {
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem 1.75rem;
  max-width: 62rem;
  margin: 0 auto;
  padding: 1.1rem 1.5rem;
}

.chrome__wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  color: var(--page-fg);
  text-decoration: none;
}

/*
 * The manicule — ☞, U+261E, the pointing hand printers set in margins, and the
 * thing the site is named after.
 *
 * It is a text character rather than an image, and that is load-bearing rather
 * than tasteful: the policy is `default-src 'none'` with no `img-src`, so this
 * site cannot load a single image. A wordmark that needed one could not ship.
 */
.chrome__manicule {
  color: var(--accent);
  font-family: var(--serif);
  font-size: 1.6rem;
  line-height: 1;
}

.chrome__name {
  font-family: var(--serif);
  font-size: 1.5rem;
  letter-spacing: -0.015em;
}

.chrome__tld {
  color: var(--faint);
}

.chrome__nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.chrome__link {
  color: var(--muted);
  font-size: 0.95rem;
  text-decoration: none;
}

.chrome__link:hover,
.chrome__link:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.chrome__link.chrome__link--current {
  color: var(--page-fg);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
}

.chrome__account {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin-left: auto;
}

.chrome__submit {
  padding: 0.45em 0.95em;
  background: var(--accent);
  color: var(--page-bg);
  border-radius: 4px;
  font-size: 0.9rem;
  text-decoration: none;
}

.chrome__submit:hover,
.chrome__submit:focus-visible {
  background: var(--page-fg);
}

.chrome__signout {
  display: inline;
}

.chrome__signout button {
  padding: 0.45em 0.9em;
  background: transparent;
  color: var(--muted);
  font-size: 0.9rem;
}

.chrome__foot {
  border-top-width: 1px;
  border-top-style: solid;
  border-top-color: var(--surface-edge);
  background: var(--surface);
}

.chrome__foot-bar {
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem;
  max-width: 62rem;
  margin: 0 auto;
  padding: 1rem 1.5rem;
  font-size: 0.85rem;
  color: var(--faint);
}

.chrome__foot-mark {
  margin-left: auto;
}

/* -- flash messages ------------------------------------------------------- */

/* Inside `.page`, so it lines up with the content it is about. */
.messages {
  margin: 0 0 1.5rem;
  padding: 0.75rem 1.1rem;
  list-style: none;
  background: var(--accent-soft);
  border-left-width: 3px;
  border-left-style: solid;
  border-left-color: var(--accent);
  border-radius: 4px;
  font-size: 0.95rem;
}

/* -- voting --------------------------------------------------------------- */

.vote {
  display: inline-flex;
  align-items: center;
  gap: 0.2em;
}

.vote__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2rem;
  padding: 0.25em 0.35em;
  border-width: 1px;
  border-style: solid;
  border-color: transparent;
  border-radius: 3px;
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.8rem;
  line-height: 1;
}

.vote__button:hover,
.vote__button:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}

/*
 * The abstention's glyph: the up arrow stacked onto the down arrow, which
 * closes into a diamond, then turned a quarter turn - so it reads as the pair
 * of them cancelling rather than as a third direction.
 *
 * Built out of the two characters the other buttons use rather than drawn as a
 * new symbol, so it stays in the reader's own font at the reader's own weight
 * and cannot end up as a glyph the other two are not.
 */
.vote__diamond {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  line-height: 0.5;
  transform: rotate(90deg);
}

/* -- listings ------------------------------------------------------------- */

/*
 * The plain list of posts. Stage 7 built this to be final: it is also the phone
 * view of the newspaper front page, its second page, and every board's listing,
 * so it is not a stepping stone to be replaced.
 *
 * The numbers the list used to carry are still absent, and there is nothing
 * here that could carry one — a post's public form has no score, no vote count
 * and no tier (§3.4). What is on screen is a title, a name, a quarter hour, a
 * board, a comment count and a coarse flag.
 */
.posts {
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * The vote cluster sits in a gutter cut out of the row's left padding, rather
 * than in a flex column beside the text.
 *
 * That is deliberate. The controls are **not always there** — they are gone
 * once this account has voted (§4.2) — and in a flex row their absence would
 * slide every title left, so a page would be ragged wherever a reader had voted
 * on some posts and not others. A gutter is the same width whether or not
 * anything is standing in it.
 *
 * The gutter itself is only cut when the reader can vote at all, which is the
 * `--votable` modifier below. A signed-out page never grows a single vote
 * control, so an empty gutter down its left edge would be indenting the whole
 * listing away from nothing.
 */
.post {
  position: relative;
  padding: 0 0 1.35rem;
  margin: 0 0 1.35rem;
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--rule);
}

.posts.posts--votable .post {
  padding-left: 3.25rem;
}

.post:last-child {
  margin-bottom: 0;
  border-bottom-width: 0;
}

.posts .post > .vote {
  position: absolute;
  top: 0.2rem;
  left: 0;
  flex-direction: column;
  gap: 0.1rem;
}

/*
 * The title carries no size of its own. A listing sets one below; on the post
 * page the same class sits inside an `<h1>` and takes the heading's, so the two
 * cannot get out of step by one of them being forgotten.
 */
.post__title {
  font-family: var(--serif);
  color: var(--page-fg);
  text-decoration: none;
}

.posts .post__title {
  font-size: 1.35rem;
  line-height: 1.3;
}

.post__title:hover,
.post__title:focus-visible {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.post__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.85rem;
  margin: 0.4rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.post__meta a {
  color: var(--muted);
  text-decoration: none;
}

.post__meta a:hover,
.post__meta a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.post__meta .post__comments {
  font-weight: 600;
}

.post__report {
  color: var(--faint);
}

/*
 * An anonymous author, in the treatment identity.css gives the anonymous
 * composer: spaced small capitals, off the polarity axis entirely. Never
 * inverted — inversion means alt, and one of the two publishes a name (§5.6).
 *
 * The base class is on the element as well as the modifier, which is what lets
 * this be written doubled. A modifier written singly loses to any base rule
 * further down the file, and `test_every_modifier_outranks_the_base_rules`
 * refuses it.
 */
.post__author.post__author--anonymous {
  font-variant: small-caps;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/*
 * "needs votes" — the one coarse flag derived from a vote figure that §3.4
 * allows out. A dotted edge, because dotted is the anonymous treatment's
 * signal and this is the other thing on the page that belongs to no persona.
 */
.post__needs-votes {
  padding: 0.1em 0.55em;
  border-width: 1px;
  border-style: dotted;
  border-color: var(--accent);
  border-radius: 3px;
  color: var(--accent);
  font-size: 0.78rem;
  font-variant: small-caps;
  letter-spacing: 0.07em;
}

.posts__more {
  margin: 1.75rem 0 0;
}

.posts__more a {
  display: inline-block;
  padding: 0.6em 1.4em;
  background: var(--surface);
  border-width: 1px;
  border-style: solid;
  border-color: var(--surface-edge);
  border-radius: 4px;
  color: var(--muted);
  font-size: 0.95rem;
  text-decoration: none;
}

.posts__more a:hover,
.posts__more a:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}

/* The two orderings, as a tab row under the heading. */
.sorts {
  display: flex;
  gap: 1.5rem;
  margin: 0 0 1.75rem;
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--rule);
}

.sorts a {
  padding: 0 0 0.6rem;
  border-bottom-width: 2px;
  border-bottom-style: solid;
  border-bottom-color: transparent;
  color: var(--muted);
  font-size: 0.95rem;
  text-decoration: none;
}

.sorts a:hover,
.sorts a:focus-visible {
  color: var(--accent);
}

.sorts a[aria-current="page"] {
  border-bottom-color: var(--accent);
  color: var(--page-fg);
  font-weight: 600;
}

/* -- the newspaper front page --------------------------------------------- */

/*
 * Stage 7, landing B. The Top ordering arranged by prominence.
 *
 * **Every size on this page is a property of a band, and a band is a position
 * in the ordering** — `content/frontpage.py` slices the list and this file
 * dresses the slices. Nothing here reads a score or a tier, because nothing
 * that reaches a template carries one (§3.4). If a rule ever needs to know
 * *why* a post is where it is, the answer is that it may not.
 *
 * Grid, and no JavaScript anywhere — the policy is `script-src 'none'`. The
 * whole layout is two columns that become one, which is all a newspaper front
 * page structurally is.
 */
.front {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 18rem;
  gap: 2.5rem;
  padding-top: 0.5rem;
}

/*
 * One column on a narrow screen, and the order the markup is already in —
 * lead, secondary, then the rails. That collapsed state is the plain listing
 * this stage's landing A built, which is why that row was built to be final.
 */
@media (max-width: 70rem) {
  .front {
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
  }
}

.front__secondary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.75rem;
  margin-top: 1.75rem;
  padding-top: 1.75rem;
  border-top-width: 1px;
  border-top-style: solid;
  border-top-color: var(--rule-strong);
}

@media (max-width: 48rem) {
  .front__secondary {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
  }
}

/* The hairlines between the secondary columns, newspaper fashion. */
.front__secondary .story.story--secondary + .story.story--secondary {
  padding-left: 1.75rem;
  border-left-width: 1px;
  border-left-style: solid;
  border-left-color: var(--rule);
}

@media (max-width: 48rem) {
  .front__secondary .story.story--secondary + .story.story--secondary {
    padding-left: 0;
    padding-top: 1.5rem;
    border-left-width: 0;
    border-top-width: 1px;
    border-top-style: solid;
    border-top-color: var(--rule);
  }
}

.front__rails {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  min-width: 0;
}

@media (max-width: 70rem) {
  .front__rails {
    padding-top: 1.75rem;
    border-top-width: 1px;
    border-top-style: solid;
    border-top-color: var(--rule-strong);
  }
}

/* The board a story is in, as a kicker above the headline. */
.story__kicker {
  margin: 0 0 0.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.story__kicker a {
  color: var(--accent);
  text-decoration: none;
}

.story__kicker a:hover,
.story__kicker a:focus-visible {
  text-decoration: underline;
}

.story__headline {
  margin: 0 0 0.6rem;
  font-weight: 400;
  letter-spacing: -0.015em;
}

.story.story--lead .story__headline {
  font-size: 2.6rem;
  line-height: 1.08;
}

@media (max-width: 48rem) {
  .story.story--lead .story__headline {
    font-size: 2rem;
  }
}

.story.story--secondary .story__headline {
  font-size: 1.3rem;
  line-height: 1.22;
}

.story__standfirst {
  margin: 0 0 0.8rem;
  font-family: var(--serif);
  color: var(--ink-soft);
}

.story.story--lead .story__standfirst {
  max-width: 34em;
  font-size: 1.15rem;
  line-height: 1.6;
}

.story.story--secondary .story__standfirst {
  font-size: 0.97rem;
  line-height: 1.55;
}

.story__byline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.8rem;
  margin: 0 0 0.5rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.story__byline a {
  color: var(--muted);
  text-decoration: none;
}

.story__byline a:hover,
.story__byline a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.story__byline .post__comments {
  font-weight: 600;
}

/* -- the two rails -------------------------------------------------------- */

.rail__heading {
  margin: 0 0 0.35rem;
  padding-bottom: 0.35rem;
  border-bottom-width: 2px;
  border-bottom-style: solid;
  border-bottom-color: var(--rule-strong);
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.rail__items {
  margin: 0;
  padding: 0;
  list-style: none;
}

.rail__item {
  padding: 0.9rem 0;
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--rule);
}

.rail__item:last-child {
  border-bottom-width: 0;
}

.rail__headline {
  margin: 0 0 0.3rem;
  font-size: 1.02rem;
  font-weight: 400;
  line-height: 1.28;
}

.rail__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem 0.6rem;
  margin: 0 0 0.35rem;
  font-size: 0.78rem;
  color: var(--muted);
}

.rail__meta a {
  color: var(--muted);
  text-decoration: none;
}

.rail__meta a:hover,
.rail__meta a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.rail__more {
  margin: 0.9rem 0 0;
  font-size: 0.82rem;
}

.rail__more a {
  font-weight: 600;
  text-decoration: none;
}

.rail__more a:hover,
.rail__more a:focus-visible {
  text-decoration: underline;
}

/* -- one post's own page -------------------------------------------------- */

/*
 * The same `.post` block, so the row and the page cannot drift apart, with the
 * listing's separator taken off: there is nothing below it to be separated
 * from.
 */
.post.post--detail {
  padding-bottom: 0;
  margin-bottom: 2rem;
  border-bottom-width: 0;
}

.post.post--detail h1 {
  margin: 0.6rem 0 0;
}

.post__body {
  max-width: var(--measure);
  margin-top: 1.25rem;
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.7;
}

.board__description {
  max-width: var(--measure);
  margin: -0.5rem 0 1.5rem;
  color: var(--muted);
}

/* The reading preference, kept quiet: it is not an action (§1.5a). */
.hidden-toggle {
  display: inline;
  margin-top: 2rem;
}

.hidden-toggle button {
  background: transparent;
  color: var(--faint);
  font-size: 0.85rem;
}

/* -- the board directory -------------------------------------------------- */

.boards {
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: var(--measure);
}

.boards__item {
  padding: 0 0 1.1rem;
  margin: 0 0 1.1rem;
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--rule);
}

.boards__name {
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--page-fg);
  text-decoration: none;
}

.boards__name:hover,
.boards__name:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.boards__address {
  margin-left: 0.6rem;
  color: var(--faint);
  font-size: 0.85rem;
}

.boards__description {
  margin: 0.3rem 0 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* -- the composer --------------------------------------------------------- */

/*
 * One box per persona, only one of them on screen, and the swap driven entirely
 * by which radio is checked.
 *
 * The radios are hidden without being removed. `display: none` would take them
 * out of the tab order and out of the accessibility tree, and the labels below
 * would then point at controls nobody using a keyboard could reach.
 */
.composer__pick {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.composer__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
  margin-bottom: 1rem;
}

.composer__tab {
  cursor: pointer;
}

/*
 * Which persona is chosen, marked on its own label. An outline rather than a
 * change of colour or border, because all three of those are already saying
 * which persona the label *is* - main, alt or anonymous - and overwriting one
 * of them here would break the mapping the whole treatment rests on.
 *
 * The outline reads --page-fg and never currentColor, and that is not a style
 * preference. An alt surface is inverted, so its currentColor *is* the page's
 * background - an outline drawn in it lands white on white and disappears. The
 * alt is the one persona whose selection has to be unmistakable, so it was
 * exactly the one that had no visible mark. --page-fg is the page's own
 * contrasting colour and works against the page in both themes. The same
 * applies to the focus rings below and to the box's own focus-within ring.
 */
.composer__pick.composer__pick--a:checked ~ .composer__tabs .composer__tab.composer__tab--a,
.composer__pick.composer__pick--b:checked ~ .composer__tabs .composer__tab.composer__tab--b,
.composer__pick.composer__pick--c:checked ~ .composer__tabs .composer__tab.composer__tab--c {
  outline-width: 2px;
  outline-style: solid;
  outline-color: var(--page-fg);
  outline-offset: 3px;
}

.composer__pick.composer__pick--a:focus-visible ~ .composer__tabs .composer__tab.composer__tab--a,
.composer__pick.composer__pick--b:focus-visible ~ .composer__tabs .composer__tab.composer__tab--b,
.composer__pick.composer__pick--c:focus-visible ~ .composer__tabs .composer__tab.composer__tab--c {
  outline-width: 3px;
  outline-style: dotted;
  outline-color: var(--page-fg);
  outline-offset: 3px;
}

/* Until a persona is picked there is no box, and the question is on screen. */
.composer__box {
  display: none;
  max-width: 46em;
  padding: 1rem 1.25rem;
  border-radius: 12px;
  border-width: 2px;
  border-color: currentColor;
}

.composer__pick.composer__pick--a:checked ~ .composer__boxes .composer__box.composer__box--a,
.composer__pick.composer__pick--b:checked ~ .composer__boxes .composer__box.composer__box--b,
.composer__pick.composer__pick--c:checked ~ .composer__boxes .composer__box.composer__box--c {
  display: block;
}

.composer__pick.composer__pick--a:checked ~ .composer__prompt,
.composer__pick.composer__pick--b:checked ~ .composer__prompt,
.composer__pick.composer__pick--c:checked ~ .composer__prompt {
  display: none;
}

.composer__box:focus-within {
  outline-width: 2px;
  outline-style: solid;
  outline-color: var(--page-fg);
  outline-offset: 2px;
}

.composer__identity {
  margin: 0 0 0.75rem;
  padding-bottom: 0.6rem;
  font-size: 0.85em;
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: currentColor;
  opacity: 0.85;
}

.composer__name {
  font-weight: 600;
}

.composer__box .acting__field {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
}

/*
 * **Everything inside a box takes its colours from the box, never from a
 * token.** The alt box is inverted, so a fixed colour that reads correctly on
 * the page reads as dark-on-dark in here — which is exactly what happened to
 * the field labels below when stage 7 gave them `--muted`.
 *
 * `transparent` and `currentColor` are the two values that follow the
 * inversion, so they are the only ones this section may use.
 *
 * `select` is listed so the board dropdown matches the Title and URL fields
 * beside it. It keeps the browser's own arrow: drawing one would need a
 * background image, and `default-src 'none'` sets no `img-src`, so it would
 * not load.
 */
.composer__box input,
.composer__box select,
.composer__box textarea {
  width: 100%;
  padding: 0.4em 0.5em;
  background: transparent;
  color: inherit;
  border-width: 1px;
  border-style: solid;
  border-color: currentColor;
  border-radius: 4px;
  font-family: inherit;
  font-size: inherit;
}

/*
 * The field labels — "Board", "Title", "URL".
 *
 * The site-wide rule paints a label in `--muted`, a dark warm grey chosen
 * against paper. Inside the inverted alt box that lands dark-on-dark and the
 * labels were close to unreadable. They inherit the box's own colour instead,
 * and stay secondary by size and weight rather than by being dimmed.
 */
.composer__box label {
  color: inherit;
  font-size: 0.85rem;
  font-weight: 600;
}

/*
 * A focus ring *inside* a box, which is the opposite case to the ring around
 * one. The box's own ring is drawn on the page and so reads `--page-fg`; these
 * are drawn on the box, and inside an inverted box `--page-fg` is the colour
 * the box is filled with. `currentColor` is the one that follows the box.
 */
.composer__box input:focus-visible,
.composer__box select:focus-visible,
.composer__box textarea:focus-visible {
  outline-color: currentColor;
}

.composer__box textarea {
  min-height: 6em;
  resize: vertical;
}

.composer__prompt {
  max-width: 46em;
}

/*
 * The three treatments.
 *
 * comment-composer-spec.md gives the inverted, dark-surfaced box to the
 * unattributed variant. **This site already gives inversion to the alt**, in
 * identity.css, and the comment there sets out why the anonymous surface
 * specifically must not invert: an inverted anonymous box and an inverted alt
 * box would be confusable at a glance, and one of them publishes a name.
 *
 * So the site's mapping wins, on the spec's own rule 2 - consistency is worth
 * more than cleverness, and one inconsistent context breaks the mapping
 * everywhere. Everything else the spec asks for is here: polarity as the
 * primary channel, monospace as the categorical cue for the box that carries no
 * name, the identity spelled out in words above the box, and the persona named
 * again inside the button that commits.
 */
.composer__box.composer__box--main {
  background: var(--page-bg);
  color: var(--page-fg);
  border-style: solid;
  font-style: normal;
}

.composer__box.composer__box--alt {
  background: var(--page-fg);
  color: var(--page-bg);
  border-style: dashed;
  font-style: italic;
}

.composer__box.composer__box.composer__box--anonymous {
  background: var(--page-bg);
  color: var(--page-fg);
  border-style: dotted;
  font-style: normal;
  /*
   * No web font can load - the policy is default-src 'none' and sets no
   * font-src - so this is the reader's own monospace face and nothing else.
   */
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.composer__box.composer__box.composer__box--anonymous .composer__identity {
  font-variant: small-caps;
  letter-spacing: 0.08em;
}

/* -- comments ------------------------------------------------------------- */

/*
 * A thread renders as a flat run of articles, each carrying its own depth as a
 * class. Nesting would need a recursive template and would put the indent cap
 * in a second place.
 *
 * **The depth must be a class and never a `style=` attribute.** The content
 * security policy sets `style-src 'self'` with no `'unsafe-inline'`, so an
 * inline style is refused by the browser and the whole thread renders flat. One
 * rule per level is the cost of that, and it is a small one.
 *
 * The nine rules below stop at eight, which is `threads.MAX_INDENT_DEPTH`.
 * Anything deeper is still nested in the data and still ordered correctly; only
 * the left margin stops moving, so a long argument still fits on a phone.
 * `test_comment_rendering` asserts the two numbers agree.
 */

/*
 * The rule down the left is the thread's structure, so it reads as a hairline
 * rather than in the text's own colour — `currentColor` here put a full-weight
 * ink bar beside every comment and turned a thread into a barcode.
 */
.comment {
  margin: 0 0 0.9rem;
  padding-left: 0.9em;
  border-left-width: 1px;
  border-left-style: solid;
  border-left-color: var(--rule);
  opacity: 1;
}

.comment.comment--depth-0 { margin-left: 0; }
.comment.comment--depth-1 { margin-left: 1.5em; }
.comment.comment--depth-2 { margin-left: 3em; }
.comment.comment--depth-3 { margin-left: 4.5em; }
.comment.comment--depth-4 { margin-left: 6em; }
.comment.comment--depth-5 { margin-left: 7.5em; }
.comment.comment--depth-6 { margin-left: 9em; }
.comment.comment--depth-7 { margin-left: 10.5em; }
.comment.comment--depth-8 { margin-left: 12em; }

.comment__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.7rem;
  margin: 0 0 0.3em;
  font-size: 0.85rem;
  color: var(--muted);
}

.comment__meta a {
  color: var(--muted);
  text-decoration: none;
}

.comment__meta a:hover,
.comment__meta a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

/*
 * An anonymous author, in the same treatment the composer's anonymous box
 * uses — spaced small capitals, off the polarity axis entirely. Never inverted:
 * inversion means alt, and an inverted anonymous line beside an inverted alt box
 * would be confusable at a glance when one of them publishes a name.
 * (CLAUDE.md §5.6, and comment-composer-spec.md rule 2.)
 */
.comment__author.comment__author--anonymous {
  font-variant: small-caps;
  letter-spacing: 0.06em;
}

.comment__body {
  max-width: var(--measure);
  margin: 0;
}

.comment__body p {
  margin: 0 0 0.4em;
}

/*
 * Reply and Report, each in its own paragraph in the template. Laid out inline
 * so the pair reads as one row of actions rather than as two stacked
 * sentences.
 */
.comment__actions {
  display: inline-block;
  margin: 0.25em 0.9em 0 0;
  font-size: 0.85rem;
}

.comment__actions a {
  color: var(--muted);
  text-decoration: none;
}

.comment__actions a:hover,
.comment__actions a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.comments {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top-width: 1px;
  border-top-style: solid;
  border-top-color: var(--rule);
}

.comments__none {
  color: var(--muted);
}

.composer-section {
  margin-top: 2rem;
}

.reply__context {
  max-width: var(--measure);
  margin-bottom: 1rem;
  padding: 0.8rem 1rem;
  background: var(--surface);
  border-radius: 6px;
  font-size: 0.9rem;
  color: var(--muted);
}

/*
 * Where a post or comment was removed by the operator (CLAUDE.md §5.7). One
 * word, quiet, and the same whoever wrote the thing — no treatment that could
 * read as main, alt or anonymous. Not italic: italic is the alt's signal on
 * action surfaces (§5.6), and borrowing it here would blur that.
 */
/*
 * Colour only, and deliberately no type treatment at all.
 *
 * The note must look the same whoever wrote the thing — main, alt or anonymous
 * (§5.7) — so it cannot borrow any of the three signals. Not italic, which is
 * the alt's, as the note above this block has always said; and not spaced small
 * capitals either, which are the anonymous treatment's, and which would make
 * every removed post read as an anonymous one.
 */
.post__removed,
.comment__removed {
  margin: 0;
  color: var(--faint);
}
