Jump to content
Toggle menu
  • 1 articles
  • 7 files
  • 3 users
  • 102 edits
Shroudforge
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Countdown/styles.css

From Shroudforge
Revision as of 21:58, 27 August 2026 by starcitizen>Alistar Bot (Name the flat reservation and count the hairline it lies under, so the last pixel of shift goes too (via update-page on MediaWiki MCP Server))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
/* Module:Countdown
 *
 * Two states. Before the gadget runs — and forever, without JavaScript — the
 * element holds a date range and is styled as a plain readout. Once the gadget
 * has built the digit stack it replaces that range with a label and three units
 * and adds `t-countdown--live`, and the rules below take over. The range is
 * dropped rather than hidden: the stack says everything it said and more, so
 * keeping it would only have assistive tech read the same span of time twice.
 *
 * The gadget also adds one of three tense classes — `--upcoming`, `--running`,
 * `--ended` — which is what the colour keys off. Nothing here reaches outside
 * the countdown element, which is the point: the card hosting it never has to
 * learn what a clock is.
 *
 * ARRANGEMENT. The clock stands its units in a column by default, for a card
 * that gives it a slot down one side, and lies them down into a strip when
 * there is no such slot. Two things ask for the strip, and they are different
 * questions: below 639px the media query does, because every card is stacked
 * there; and at any width `--flat` does, for a card that is stacked throughout
 * and therefore has no viewport question to ask. A card must never restyle the
 * clock itself — the arrangement is the clock's, the slot is the card's.
 */
.t-countdown {
	/* The caption's size, named because three rules need it: the caption draws
	 * itself with it, and the reservation below is measured in it. */
	--countdown-caption: 0.62rem;
	/* One unit, as tall as the gadget will build it. The digits carry
	 * line-height 1, so they are exactly their own size; the caption adds its
	 * own height plus the 0.25em that separates them, hence the 1.25. */
	--countdown-unit: calc(var(--countdown-size, 3rem) + var(--countdown-caption) * 1.25);
	/* The reservation for a clock lying down: one unit row, not four. Named
	 * rather than repeated because all three arrangements that lie the clock
	 * down need it, and they already have enough to keep in step.
	 *
	 * The trailing 1px is the hairline. Lying down it runs across the BLOCK
	 * axis, and box-sizing is border-box, so it counts against the height —
	 * standing up the same hairline is on the inline edge and costs nothing,
	 * which is why the reservation below has no such term. */
	--countdown-reserve-flat: calc(var(--countdown-unit) + var(--space-md) * 2 + 1px);
	flex: none;
	display: flex;
	flex-direction: column;
	justify-content: center;
	/* THE COLUMN THE CLOCK STANDS IN, pinned rather than left to its content,
	 * and the shift is only the first of two reasons.
	 *
	 * The range and the units are different widths — 268px against 87 — so
	 * going live shrank the clock by 181 and rewrapped the card's prose beside
	 * it. And left to itself the column's width depends on how long the DATE in
	 * the settings happens to be, so an event running into September gave the
	 * body less room to set than one running into May. Neither is something the
	 * card next to it should be able to feel.
	 *
	 * 7rem leaves 80px of content box once the padding is out, which clears
	 * both sides: the units need 54px, and the range's longest unbreakable word
	 * is "September" at 76. All three arrangements that lie the clock down
	 * already set `inline-size: 100%`, so this needs no reset of its own. */
	inline-size: 7rem;
	padding: var(--space-md);
	/* THE ROOM THE CLOCK WILL NEED, reserved before it needs it: a label row and
	 * three unit rows. The two states hold different things — a date range now,
	 * a label and three counters once the gadget runs — and left to themselves
	 * they are different heights, so going live grew the card under the reader
	 * and pushed every band below it down the page (11px standing up, 30px
	 * lying down, measured). Reserving the taller of the two in BOTH means the
	 * swap changes what the clock says and never how much room it takes.
	 *
	 * Derived from the same tokens that draw a unit rather than measured off a
	 * screenshot, so it cannot drift from what it is reserving for. */
	min-block-size: calc(var(--line-height-x-small) + var(--countdown-unit) * 3 + var(--space-md) * 2);
	font-family: var(--font-family-monospace);
	text-align: center;
	/* THE TENSE COLOUR, set once here and inherited. The label and the digits
	 * are halves of one statement — what this is, and how long — so they take
	 * one colour between them, and each tense below has a single declaration to
	 * change rather than one per part. Only the unit captions opt back out. */
	color: var(--color-subtle);
	/* The hairline is the clock's own edge, not the card's: the card takes a
	 * content slot and has no business deciding that whatever lands in it gets a
	 * rule. Logical so it follows the flex row's direction rather than assuming
	 * the clock is always on the right. It runs the full height of the card,
	 * meeting the border top and bottom. */
	border-inline-start: var(--border-subtle);
}

.t-countdown__fallback {
	font-size: var(--font-size-small);
	line-height: var(--line-height-small);
	/* Standing up the range wraps down a narrow column, so a date whose longest
	 * word outgrows it breaks rather than hangs out of the card. Insurance:
	 * "September" is the longest word any English date produces and it fits. */
	overflow-wrap: break-word;
}

/* Deliberately the same size and tracking as Module:CardLua's kicker: the two
 * sit at opposite ends of the card's head and share a top and bottom edge, so
 * anything smaller here breaks that line. */
.t-countdown__label {
	font-size: var(--font-size-x-small);
	line-height: var(--line-height-x-small);
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* Live: the unit rows share whatever height the card has, so the clock fills
 * its column instead of clustering. Sizing the digits BY the height would want
 * `cqh`, which needs `container-type` — rejected by the TemplateStyles
 * sanitizer — so the digits stay on a scale and the rows do the adapting. */
.t-countdown--live {
	display: grid;
	grid-template-rows: auto;
	grid-auto-rows: 1fr;
	align-items: center;
	justify-items: center;
}

.t-countdown__unit {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	line-height: 1;
}

.t-countdown__value {
	/* 3rem is the ceiling before the clock, rather than the card's content,
	 * starts deciding how tall the row is. */
	font-size: var(--countdown-size, 3rem);
	font-weight: var(--font-weight-medium);
	letter-spacing: -0.04em;
	/* Tabular figures so the stacked numbers line up: without it a 1 is
	 * narrower than a 0 and the column reads ragged. */
	font-variant-numeric: tabular-nums;
}

/* The plain number behind each reel — what assistive tech reads instead of a
   column of digits. The class is the gadget's to apply but this stylesheet's to
   define: the odometer markup is shared with the hero, and only the component it
   was built inside knows which stylesheet is guaranteed to be on the page. */
.t-countdown__sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset( 50% );
	white-space: nowrap;
}

.t-countdown__unit-label {
	font-size: var(--countdown-caption);
	line-height: 1;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	/* The one part that opts out: the captions name the units and are not part
	 * of the statement the tense is colouring. */
	color: var(--color-subtle);
	margin-top: 0.25em;
}

/* ---- Tense --------------------------------------------------------------
 * Colour is reinforcement here, never the only carrier: the label already says
 * "Coming", "Ends" or "Ended" in words, so nothing is lost on a monochrome
 * display or to a screen reader, and no visually-hidden partner is owed.
 *
 * The stripe is Module:Entity/Ports' overlay retuned for the area. Ports draws
 * 2px lines on a 6px period at alpha 0.10 over a 32px pill; the same rule here
 * covers roughly twenty times that, and its average lift — duty cycle times
 * alpha, 0.033 — visibly washes the colour underneath toward grey. The line
 * weight stays at 2px because that is the house signature; the spacing and the
 * alpha come down, landing at a lift of 0.012, about a third of Ports.
 */
.t-countdown--running,
.t-countdown--upcoming {
	background-image: repeating-linear-gradient(
		-45deg,
		light-dark(rgba(0, 0, 0, 0.03), rgba(255, 255, 255, 0.06)),
		light-dark(rgba(0, 0, 0, 0.03), rgba(255, 255, 255, 0.06)) 2px,
		transparent 2px,
		transparent 10px
	);
}

.t-countdown--running {
	color: var(--color-success);
	background-color: var(--background-color-success-subtle);
	border-inline-start-color: var(--border-color-success);
}

.t-countdown--upcoming {
	color: var(--color-warning);
	background-color: var(--background-color-warning-subtle);
	border-inline-start-color: var(--border-color-warning);
}

/* Ended has no rule, and needs none: claiming no tense means taking no tense
 * colour, so it falls back to the subtle the root already sets. That is
 * `--color-subtle` rather than `--color-disabled` on purpose — the number still
 * carries a fact worth reading, how long ago and so how stale the card is. It
 * is past, not inert. */

/* ---- Lying down ----------------------------------------------------------
 * The strip. `display` has to be reset explicitly: the live state is a grid,
 * and flex-direction is inert on a grid, so flipping the direction alone would
 * silently leave the units stacked.
 *
 * These rules must stay BELOW the tense block. They are single-class like it,
 * so which wins is decided on source order, and the strip has to be able to
 * move the tense colour from the inline edge to the block edge.
 *
 * The declarations appear twice, here and in the media query at the foot,
 * because one is asked for by a class and the other by a viewport and CSS
 * cannot share a block across a media query. Keep them identical.
 */
.t-countdown--flat,
.t-countdown--flat.t-countdown--live {
	display: flex;
	flex-direction: row;
	/* The units end-align as a group; the auto margin below holds the label at
	 * the start. Both together, so the strip reads left to right as what this
	 * is and then how long, with the empty space between the two rather than
	 * spread through them the way space-between would. */
	justify-content: flex-end;
	align-items: flex-end;
	gap: var(--space-md);
	inline-size: 100%;
	/* Lying down, the rule that divided two columns becomes the one that
	 * divides two rows. */
	border-inline-start: 0;
	border-block-start: var(--border-subtle);
	/* Three units abreast rather than stacked down a column: at 3rem the strip
	 * dominates the card it is attached to. */
	--countdown-size: 2.5rem;
	/* One row now, not four, and the label is shorter than a unit. */
	min-block-size: var(--countdown-reserve-flat);
}

.t-countdown--flat .t-countdown__label,
.t-countdown--flat .t-countdown__fallback {
	margin-inline-end: auto;
}

.t-countdown--flat.t-countdown--running {
	border-block-start-color: var(--border-color-success);
}

.t-countdown--flat.t-countdown--upcoming {
	border-block-start-color: var(--border-color-warning);
}

.t-countdown--flat.t-countdown--live .t-countdown__label {
	align-self: center;
}

/* Narrow lies every clock down, whether its card asked or not. */
@media (max-width: 639px) {
	.t-countdown,
	.t-countdown--live {
		display: flex;
		flex-direction: row;
		justify-content: flex-end;
		align-items: flex-end;
		gap: var(--space-md);
		inline-size: 100%;
		border-inline-start: 0;
		border-block-start: var(--border-subtle);
		--countdown-size: 2.5rem;
		min-block-size: var(--countdown-reserve-flat);
	}

	.t-countdown__label,
	.t-countdown__fallback {
		margin-inline-end: auto;
	}

	.t-countdown--running {
		border-block-start-color: var(--border-color-success);
	}

	.t-countdown--upcoming {
		border-block-start-color: var(--border-color-warning);
	}

	.t-countdown--live .t-countdown__label {
		align-self: center;
	}
}

/* Note what lying down does NOT change: alignment inside a unit. Each unit
 * centres its digits over its own caption either way, so the clock reads the
 * same on its side as it does standing up. Only the axis changes. */
Last modified
Copyright