/*
 * Application-wide styles. Tailwind lives in app/assets/tailwind/application.css; Propshaft serves
 * both, and stylesheet_link_tag :app picks up everything on the load path.
 */

/*
 * One focus indicator for everything interactive, rather than a utility class repeated on each
 * element and forgotten on some. :focus-visible keeps it off mouse clicks and on for keyboards.
 *
 * :where() keeps specificity at zero, so any element that needs a different indicator can override
 * this without !important.
 */
:where(a[href], button, input, select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid #1d4ed8; /* blue-700: 6.3:1 on white, and it survives projection */
  outline-offset: 2px;
  border-radius: 2px;
}

/*
 * The game master's console is projected or shared over Zoom, both of which wash out mid-tones.
 * Nothing here should rely on a hairline.
 */

/*
 * The participant screen pins the budget to the top of the viewport, and a pinned bar can cover the
 * control a keyboard user has just tabbed back to — WCAG 2.2 SC 2.4.11, Focus Not Obscured. axe
 * cannot catch it, because whether it happens depends on where the page is scrolled when focus
 * lands.
 *
 * Chrome scrolls in steps and leaves 31px of clearance at its closest, so today the rule is not
 * what is saving us — but 31px is the whole margin, and the bar is one Tailwind class away from
 * being taller than that. WorkspaceTest keeps the bar's height under this value for exactly that
 * reason.
 *
 * Global and at zero specificity for the same reason the focus ring is: per-element scroll margins
 * get forgotten on the next element somebody adds. On screens with nothing pinned it only means
 * focus lands a little lower.
 */
:where(a[href], button, input, select, textarea, summary, [tabindex]:not([tabindex="-1"])) {
  scroll-margin-top: 6rem;
}

/* A control card carries `flex`, and the filter hides it with the `hidden` attribute. Tailwind's
   preflight rule for [hidden] and the .flex utility have the same specificity, so the utility wins
   on source order and a hidden card stays on screen. The attribute is the right mechanism — it
   takes the row out of the accessibility tree as well as the layout — so raise it rather than
   swapping it for a class. */
[hidden] {
  display: none !important;
}

/*
 * Control cards are printed on a ground so a board of ten reads as a board rather than as a list.
 * This replaced a 45-degree hatch drawn with a gradient, which did the same job with no asset to
 * ship; what the tiles buy over it is that they differ from one another, and so can carry the
 * risk area.
 *
 * One tile per area, and the pairing is decoration rather than taxonomy — grass means nothing
 * about Workforce. The badge at the top of the card names the family in words, and the ground
 * only repeats it, so a participant who cannot tell ferns from grass has lost nothing. What it
 * buys is that a board sorted by code still groups by family at arm's length, which is what a
 * trading card game gets from the colour of its cards.
 *
 * Eight tiles from a set of twelve. The four left out are worth naming, because the reasons are
 * not visible in what remains: clouds is a flat lavender close enough to bg-blue-50 that an
 * unowned Governance card looked bought; forest shows a hard horizontal band at every tile join;
 * canopy and lichen are hard to tell from ferns and pebbles at arm's length. Tiles are 320 x 255
 * and repeat. A card is 350 wide on a phone and taller than 255, so both joins fall inside it —
 * check any new tile for a seam by tiling it at 350 x 600 and looking, which is the test forest
 * fails and no summary statistic caught.
 *
 * The tiles are opaque, which is the case the hatch rule was written to avoid: background-image
 * paints over background-color, so a tile hides the bg-blue-50 that marks an owned card. The blue
 * goes back on as a wash above the tile instead of below it, which keeps the tint and the texture
 * both. The Tailwind bg-blue-50 stays on the element underneath as the fallback for an image that
 * does not load.
 *
 * Contrast was measured against the darkest pixel of each tile rather than its average, because
 * an average hides the one dark stroke a line of text happens to cross. Body text at gray-700
 * holds 5.82:1 at worst, on petals, against the 4.5:1 AA asks for; the wash lightens rather than
 * darkens, so an owned card sits higher still, at 6.21:1. Do that measurement for any tile added
 * here — axe cannot see a background image at all, since it evaluates text against background
 * *colour*, so assert_accessible will pass a ground busy or dark enough to hurt reading, and
 * nothing but a person looking at it is checking.
 */
.control-card {
  background-image: var(--card-ground);
  background-repeat: repeat;
  background-size: 320px 255px;
}

.control-card.is-owned {
  background-image:
    linear-gradient(rgb(191 219 254 / 0.30), rgb(191 219 254 / 0.30)),
    var(--card-ground);
}

/* Set by risk_ground_class. Propshaft rewrites these to digested paths. */
.ground-petals    { --card-ground: url("/assets/ground-petals-eb613cf3.webp"); }
.ground-linen     { --card-ground: url("/assets/ground-linen-f545b931.webp"); }
.ground-pebbles   { --card-ground: url("/assets/ground-pebbles-dc172f5f.webp"); }
.ground-raindrops { --card-ground: url("/assets/ground-raindrops-dc08e68a.webp"); }
.ground-waves     { --card-ground: url("/assets/ground-waves-9de6d8c2.webp"); }
.ground-ferns     { --card-ground: url("/assets/ground-ferns-0e973ba2.webp"); }
.ground-parchment { --card-ground: url("/assets/ground-parchment-fe032d76.webp"); }
.ground-grass     { --card-ground: url("/assets/ground-grass-3cc9c0a4.webp"); }

/*
 * The badge picks up its ground's own colour. Each value below is that tile's average pushed
 * 1.7x further from white, which is why there is no ninth palette here — the badge and the ground
 * are the same hue, one of them stronger.
 *
 * The tint is warmth and nothing else. A white badge is 1.11:1 against its ground, so white was
 * never what made the badge stand out; the 2px rule around it was, and still is. Label text over
 * these holds 11:1 at worst, on petals.
 */
.badge-petals { background-color: #d6cac6; }
.badge-linen { background-color: #eae6d7; }
.badge-pebbles { background-color: #e5e4da; }
.badge-raindrops { background-color: #e0e9ee; }
.badge-waves { background-color: #d9ece9; }
.badge-ferns { background-color: #e5f0df; }
.badge-parchment { background-color: #f0e5cc; }
.badge-grass { background-color: #dbe7c8; }

/*
 * The price, on a plate. It is the number the whole game turns on and it used to be set at the
 * same weight as the control's name.
 *
 * It sits on the action row rather than in the top corner, which is where a printed card would put
 * it. The corner was tried: on a 350px phone a plate there left the name 113px to wrap in, and
 * these names run to "Business Associate Agreement (BAA) with Amazon Web Services (AWS)". The
 * median card grew 24px and the worst grew 35. A fixed column to compare down is what the corner
 * was for, and the action row is one too.
 *
 * White rather than tinted, because this is the one element that must not belong to its ground:
 * a player comparing prices down a column is reading across risk areas, not within one. It also
 * gives "Owned" somewhere to sit that reads as a state rather than as a price that went missing.
 */
.price-plate {
  border: 2px solid #000;
  border-radius: 0.375rem;
  background-color: #fff;
  padding: 0.1875rem 0.5rem;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.25;
  color: #101828;
  font-variant-numeric: tabular-nums;
}

/* The pin box on the front door: a cell per symbol, with the dash where the pin is printed with
 * one. The pattern every quiz and every one-time code uses, so nobody has to be told what it is.
 *
 * Underneath it is one ordinary text input covering the whole group, not four. The cells carry no
 * text of their own — pin_entry_controller copies each symbol into them — take no tab stop, and
 * are hidden from assistive technology, so what a screen reader meets is a single labelled field.
 * Four real inputs with auto-advance is the usual build and it announces as four unlabelled boxes,
 * moves focus out from under the user, and loses three characters of a pasted code.
 *
 * Everything here is inside .is-enhanced, which the controller adds when it connects. Without
 * JavaScript the cells never appear and .pin-field is an ordinary box somebody can still type
 * into — a page whose only control is invisible until a script runs is a page that needs the
 * script.
 */
.pin-field {
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 2.25rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.4em;
  padding-left: 0.4em;
  text-transform: uppercase;
}

.pin-entry { position: relative; }

.pin-cells { display: none; }

.pin-entry.is-enhanced .pin-cells {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.25em;
  font-size: 2rem;
}

/* The field goes on covering the group so that a tap anywhere in it lands on the real control, and
   so the label still points at something the right size. Transparent rather than opacity: 0,
   because opacity would take the focus ring with it. */
.pin-entry.is-enhanced .pin-field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border-color: transparent;
  background-color: transparent;
  box-shadow: none;
  color: transparent;
  /* The caret would sit at the end of the run rather than inside a cell. .is-next is what says
     where the next symbol lands. */
  caret-color: transparent;
}

/* Sized in em from whatever font-size the group sets, so one cell serves both places the pin
   appears: the box a player types into on a phone, and the plate a room reads off a projector.
   They have to look like each other — somebody is copying one into the other. */
.pin-cell {
  display: grid;
  place-items: center;
  width: 1.6em;
  height: 2em;
  border: 0.0625em solid #9ca3af; /* gray-400, 3.0:1 on white — AA for a control boundary */
  border-radius: 0.25em;
  background-color: #ffffff;
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 600;
  line-height: 1;
  color: #101828;
}

.pin-cell.is-filled { border-color: #4b5563; } /* gray-600: a symbol has landed here */

/* The focus indicator for this control, which is why the field's own is turned off below rather
   than both being drawn. The global :focus-visible rule rings the element that has focus, and the
   element that has focus here is a transparent box the size of the whole group — so it drew a
   rounded rectangle around the four rectangles, which is one box too many.
 *
 * Weight as well as colour, because a border that says "here" only by being blue says nothing to
 * a reader who cannot tell it from the two greys above. Blue-700 is 6.3:1 on white and the width
 * doubles, so the change is visible without relying on the hue. */
.pin-entry.is-enhanced:focus-within .pin-cell.is-active {
  border-color: #1d4ed8;
  border-width: 4px;
}

.pin-entry.is-enhanced .pin-field:focus-visible { outline: none; }

/* Drawn rather than typed. A hyphen glyph at this size sits high and thin between two 4rem cells;
   a rule sits where the eye expects the separator to be. The whole group is aria-hidden, so there
   is nothing here for a screen reader to meet either way. */
.pin-dash {
  width: 0.45em;
  height: 0.08em;
  background-color: #6b7280;
}

/* The same cells, read from the back of a room rather than typed into. Projected or shared over
 * Zoom, so it is sized to survive compression and a bad angle — and it is the same component as
 * the box on the phone, because the whole job here is for somebody to copy one into the other.
 *
 * A heavier border than the form's: a hairline that reads at arm's length disappears through a
 * projector and a webcam.
 */
.pin-plate {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.25em;
  font-size: clamp(2.5rem, 9vw, 5rem);
}

.pin-plate .pin-cell {
  border-width: 0.05em;
  border-color: #4b5563; /* gray-600, 7.6:1 — it has to survive compression */
  font-weight: 700;
}

/* On the projector, where there is room and distance. */
.pin-plate.is-projected { font-size: clamp(3rem, 7vw, 6.5rem); }

/*
 * What kind of thing a control is, as a chip. Six kinds over forty-six controls, and the colour
 * is a grouping aid rather than a judgement — which is why none of them is red, green, or blue.
 * Red and green are already spoken for by the grade stamps below, where they do mean good and
 * bad; blue is the app's action colour, on the Buy button, the owned card and the focus ring. A
 * red chip on an insurance control would read as a warning about insurance.
 *
 * The word is inside the chip, so the colour is never carrying the meaning alone. Text on fill
 * holds 5.8:1 at worst, on audit.
 *
 * The border is not decoration. A chip sits on a printed ground, and a pale fill against a pale
 * tile is about 1:1 — the fill alone is invisible as a shape, and only the hairline in the text
 * colour makes the chip read as a chip rather than as coloured text.
 */
.kind-chip {
  display: inline-block;
  border: 1px solid currentColor;
  border-radius: 9999px;
  padding: 0.0625rem 0.5rem;
  font-size: 0.8125rem;
  line-height: 1.35;
  white-space: nowrap;
}

/*
 * The other two chips are monochrome, and that is the whole reason they read. Three coloured chip
 * families on one card would be three colour systems to learn; the kind is the taxonomy and keeps
 * the colour, while "Paid in cash" and "Done in weeks" are sentences short enough to be read
 * rather than decoded. They say what they mean, so they need no key.
 */
.plain-chip {
  color: #364153;
  background-color: rgb(255 255 255 / 0.75);
}

.kind-tool         { color: #334155; background-color: #eef1f6; }
.kind-process      { color: #5b21b6; background-color: #f4efff; }
.kind-service      { color: #0f5c56; background-color: #e6f6f4; }
.kind-audit        { color: #8a5300; background-color: #fdf5e3; }
.kind-architecture { color: #8f1a68; background-color: #fdeff7; }
.kind-insurance    { color: #7a4a1c; background-color: #faf1e6; }

/*
 * A count on the projected display that has just changed. The number is the tempo — you watch one
 * team jump three times in ten seconds while another has not moved in four minutes — and a number
 * that changes while nobody happens to be looking has said nothing at all. A second of colour is
 * enough to catch from the back of a room.
 *
 * Colour is not carrying anything here: the figure itself is the information, and the flash only
 * says "look now". Which is why dropping it for reduced motion loses nothing.
 */
.just-changed {
  animation: just-changed 1s ease-out 1;
}

@keyframes just-changed {
  0% { color: #1d4ed8; }
  100% { color: inherit; }
}

@media (prefers-reduced-motion: reduce) {
  .just-changed { animation: none; }
}

/*
 * The last minute of a round: a colour change and nothing else. This stage exists to be noticed
 * without being obeyed — a CISO who looks up here still has time to decide something, which is not
 * true thirty seconds later. amber-700 holds 4.6:1 on white.
 */
.countdown.is-warning .countdown-display {
  color: #bb4d00;
}

/*
 * The last thirty seconds of a round. A colour and weight change that breathes, not a strobe:
 * WCAG 2.3.1 restricts flashing, three flashes a second is the threshold, and this is a screen
 * projected in front of a room that did not consent to being flashed at.
 *
 * The colour alone carries the message, which is why the animation can be dropped entirely for
 * anyone who has asked for less motion, and why red-600 rather than a lighter red: it holds 4.5:1
 * on white and survives a projector and Zoom's compression.
 */
.countdown.is-urgent .countdown-display {
  color: #c10007; /* red-600: 4.8:1 on white */
  animation: countdown-pulse 1s ease-in-out infinite;
}

.countdown.is-expired .countdown-display {
  color: #c10007;
  opacity: 0.6;
}

@keyframes countdown-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
  .countdown.is-urgent .countdown-display {
    animation: none;
  }
}

/*
 * The grade, stamped. Square, monospaced, and rotated a little, because the card language it sits
 * next to is a printed one — see app/views/teams/_controls.html.erb.
 *
 * Colour is never the only signal: the letter itself says everything the colour does, which is
 * what makes this legible to a colour-blind participant, on a washed-out projector, and in a Zoom
 * stream that has thrown away most of the mid-tones. Every pair below holds at least 4.5:1.
 */
.grade-stamp {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 3rem;
  height: 3rem;
  border: 2px solid currentColor;
  border-radius: 0.375rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  transform: rotate(-4deg);
}

.grade-a { color: #106a3f; background-color: #eefbf3; }
.grade-b { color: #1447e6; background-color: #eff6ff; }
.grade-c { color: #9a5b00; background-color: #fffbeb; }
.grade-d { color: #b3231e; background-color: #fef2f2; }

/*
 * Disclosure panels. The default triangle is small, differs between browsers, and on a projector
 * reads as a speck — so it is replaced with a chevron that turns, and the whole summary gets a
 * hover state so it looks like something to press.
 *
 * The company panel now starts closed and is the first thing a room sees while people are still
 * arriving, so "there is more here" has to be obvious from across a room rather than on inspection.
 */
.disclosure > summary {
  list-style: none;
}

.disclosure > summary::-webkit-details-marker {
  display: none;
}

.disclosure-chevron {
  transition: transform 150ms ease;
}

.disclosure[open] > summary .disclosure-chevron {
  transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
  .disclosure-chevron { transition: none; }
}

/*
 * The last thirty seconds, across the whole screen. A tint laid over the page rather than a change
 * to the background, so it reaches a phone where the clock itself is four characters in a pinned
 * bar and nobody reading the bottom of the board would ever see it.
 *
 * One cycle a second. WCAG 2.3.1's general flash threshold is three a second over more than a
 * quarter of the visual field, and this is full-screen, so the rate is the thing keeping it safe.
 * Peak opacity is low enough that text under it stays well above 4.5:1.
 *
 * Both numbers are enforced. AccessibilityTest reads them out of the stylesheet the browser
 * parsed — not out of this file — so an override elsewhere is caught too. It has been checked
 * against a faster pulse and a deeper tint, and fails on each.
 *
 * pointer-events: none because it covers the Buy buttons, and a countdown that stopped a CISO
 * buying in the last thirty seconds would be an unusually cruel bug.
 */
body.round-urgent::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  background-color: #c10007;
  opacity: 0;
  animation: page-pulse 1s ease-in-out infinite;
}

@keyframes page-pulse {
  0%, 100% { opacity: 0; }
  50% { opacity: 0.12; }
}

/*
 * Still says the same thing without moving. A steady wash rather than nothing at all, because for
 * a reduced-motion reader the alternative is a screen that never tells them the round is ending.
 */
@media (prefers-reduced-motion: reduce) {
  body.round-urgent::after {
    animation: none;
    opacity: 0.08;
  }
}

/*
 * Typography for pages written as Markdown. The handler in
 * config/initializers/markdown_template_handler.rb wraps every .html.md render in this class.
 *
 * It exists because Markdown emits bare h1/p/ul and Tailwind's preflight resets all of them to
 * unstyled inherited text — headings included. Without these rules a prose page renders as one
 * column of identical sentences. Every selector here is a class plus an element, which outranks
 * preflight's bare element selectors no matter which sheet loads first.
 *
 * There are no utility classes to add in the Markdown, and that is the point: the author writes
 * prose and the stylesheet decides what it looks like.
 */
/* 48rem is about 80 characters at this size, which is the ceiling WCAG 1.4.8 asks for and the
   widest this column can go without reading badly. It is also what the wide figures below are now
   set to, so the prose and the screenshots share one edge instead of the pictures bulging past a
   narrower column — which was the thing that looked wrong.

   The trade is the other direction: those figures were 56rem and are now 48rem, so a projected
   board is 14% smaller than it was. Going the other way — 56rem for both — puts this column at
   roughly 95 characters, and a line that long loses the reader on the return sweep. */
.markdown-copy {
  max-width: 48rem;
  margin-inline: auto;
}

.markdown-copy > * + * { margin-top: 1rem; }

.markdown-copy h1 { font-size: 2.25rem; font-weight: 700; line-height: 1.15; }
.markdown-copy h2 { margin-top: 2.5rem; font-size: 1.5rem; font-weight: 700; line-height: 1.3; }
.markdown-copy h3 { margin-top: 2rem; font-size: 1.25rem; font-weight: 600; line-height: 1.4; }

.markdown-copy p { line-height: 1.7; }

/* The opening paragraph reads as a standfirst. Anything past the first is body copy. */
.markdown-copy > p:first-of-type { font-size: 1.125rem; }

/* blue-800 on white is 8.6:1, and matches every other link in the app. */
.markdown-copy a { color: #1e40af; text-decoration: underline; text-underline-offset: 2px; }
.markdown-copy a:hover { text-decoration: none; }

.markdown-copy ul { list-style: disc; padding-left: 1.5rem; }
.markdown-copy ol { list-style: decimal; padding-left: 1.5rem; }
.markdown-copy li { line-height: 1.7; }
.markdown-copy li + li { margin-top: 0.5rem; }

.markdown-copy strong { font-weight: 600; }

.markdown-copy blockquote {
  border-left: 3px solid #9ca3af;
  padding-left: 1rem;
  color: #374151; /* gray-700, 10.3:1 */
}

.markdown-copy code {
  border-radius: 3px;
  background-color: #f3f4f6;
  padding: 0.1em 0.3em;
  font-size: 0.9em;
}

.markdown-copy pre {
  border-radius: 6px;
  background-color: #f3f4f6;
  padding: 1rem;
  overflow-x: auto; /* a long line scrolls inside the block rather than widening the page */
}

.markdown-copy pre code { background-color: transparent; padding: 0; }

.markdown-copy hr { margin-block: 2.5rem; border-top: 1px solid #d1d5db; }

/* Screenshots. A picture of a projected board wants every pixel it can have, and it now takes the
   full prose column rather than breaking out past it: text and the widest pictures line up on the
   same two edges, which is what the column above was widened for. The phone shot is the other way
   round: it is 500px wide and portrait, and stretching it across the column would make it a
   poster. */
.markdown-copy figure { margin-top: 2rem; }
.markdown-copy figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
  border: 1px solid #d1d5db;
}
.markdown-copy figcaption {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.5;
  color: #374151; /* gray-700, 10.3:1 */
}

/* A glossed card is a drawing rather than a photograph of a screen: the card is already framed,
   and the arrows and labels beside it sit on the page's own white. The border and the rounded
   corner that frame a screenshot would be drawing a box around that white. */
.markdown-copy figure.gloss img { border: 0; border-radius: 0; }

.markdown-copy figure.phone img { max-width: 19rem; margin-inline: auto; }
.markdown-copy figure.phone figcaption { max-width: 19rem; margin-inline: auto; }

/* .wide now means "the full column" rather than "wider than the column". Kept as a class rather
   than dropped from the markup because it still says which figures are the projected board and
   which are the phone, and because the breakout may want to come back if this column narrows. */

.markdown-copy table { width: 100%; border-collapse: collapse; }
.markdown-copy th, .markdown-copy td {
  border-bottom: 1px solid #d1d5db;
  padding: 0.5rem 0.75rem;
  text-align: left;
  vertical-align: top;
}
.markdown-copy th { font-weight: 600; }

/*
 * The grade stamp at projector scale. The console's is 3rem, which is right for a laptop and a
 * speck from the back of a room — and the letter is the thing the room is waiting for.
 *
 * A modifier rather than a second class so the colours, the border and the tilt stay in one place:
 * a grade that looked different on the two screens would read as two different results.
 */
.grade-stamp-lg {
  width: 6rem;
  height: 6rem;
  font-size: 3.5rem;
  border-width: 3px;
}

/*
 * Turning a control card over to read what the team said about it.
 *
 * The two faces are stacked in the same grid cell rather than absolutely positioned, so the card
 * keeps the height of whichever face is taller and the board does not reflow as cards turn. A
 * backface that is merely rotated away still takes clicks in some browsers, so the hidden one is
 * also made inert by the controller — see flip_controller.
 */
.flip-card {
  perspective: 1200px;
}

.flip-card-faces {
  display: grid;
  transform-style: preserve-3d;
  transition: transform 450ms cubic-bezier(0.2, 0.7, 0.3, 1);
  height: 100%;
}

.flip-card-faces > * {
  grid-area: 1 / 1;
  min-width: 0;
  backface-visibility: hidden;

  /*
   * The face that is not showing is hidden outright rather than left to backface culling.
   *
   * preserve-3d does not hold on a grid container, so nothing was being culled: at rest the back
   * sat mirrored behind the front, and turned over, the front showed through the back in mirror
   * writing. Kept the property anyway for the browsers where it does work — this is the belt.
   *
   * The swap waits for half the turn, which is the moment the card is edge-on and there is nothing
   * to see it happen.
   */
  visibility: hidden;
  transition: visibility 0s linear 225ms;
}

.flip-card-faces > [data-flip-target="front"] {
  visibility: visible;
}

.flip-card.is-flipped .flip-card-faces > [data-flip-target="front"] {
  visibility: hidden;
}

.flip-card.is-flipped .flip-card-faces > [data-flip-target="back"] {
  visibility: visible;
}

.flip-card-faces > .flip-card-back {
  transform: rotateY(180deg);
}

.flip-card.is-flipped .flip-card-faces {
  transform: rotateY(180deg);
}

/*
 * A card in the middle of its turn takes no clicks.
 *
 * Halfway through, the card is edge-on: what is painted has almost nothing to do with the layout
 * box every hit test uses, so a click aimed at the middle of a button lands on whatever is behind
 * the card. flip_controller sets the attribute for the length of the turn and removes it after.
 */
.flip-card[data-flip-turning] .flip-card-faces {
  pointer-events: none;
}

/*
 * Reduced motion turns the card without turning it. The swap still has to happen — which face is
 * readable is what the control does — but it happens at once rather than over half a second, so
 * there is no rotation and nothing waiting on a delay. flip_controller checks the same query and
 * skips both the focus delay and the turning attribute.
 */
@media (prefers-reduced-motion: reduce) {
  .flip-card-faces,
  .flip-card-faces > * {
    transition: none;
  }
}

/*
 * The turn is decoration and nothing on either face depends on it, so anyone who has asked for less
 * motion gets the swap without the spin.
 */
@media (prefers-reduced-motion: reduce) {
  .flip-card-faces,
  .flip-card-faces > * { transition: none; }
}

/*
 * A Round 3 card's rows: a label in a pill, its value running on from it, both inside one thin
 * box.
 *
 * The label used to sit on its own line above the value, which cost a line per row and made a
 * six-row card taller than the screen it was read on. Running them together reclaims that, and
 * the box is what keeps the rows from reading as one paragraph once the line breaks are gone.
 * The value wraps to the left edge of its box rather than hanging under the label, which is what
 * makes the box worth drawing: the edge is the thing the eye follows down the card.
 *
 * The colour is per label, not per card, so "Identity" is the same colour on all five and a
 * reader comparing one aspect across partners can find it without reading. See
 * ProductsHelper#label_tints for how a label is assigned one, and why collisions are probed past
 * rather than allowed.
 *
 * Ink over fill runs 6.3:1 at worst, on teal. The edges are 2.8-3.4:1 against the card's ground,
 * which is a boundary you can see without the card turning into a table of ruled lines.
 */
.label-row {
  border: 1px solid var(--label-edge);
  border-radius: 0.375rem;
  background-color: rgb(255 255 255 / 0.55);
  padding: 0.3rem 0.5rem;
}

.label-row .label-pill {
  display: inline-block;
  margin-right: 0.4rem;
  border: 1px solid var(--label-edge);
  border-radius: 9999px;
  background-color: var(--label-fill);
  padding: 0.05rem 0.5rem;
  color: var(--label-ink);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.label-tint-rose    { --label-fill: #fde5e7; --label-ink: #9f1239; --label-edge: #c06a7b; }
.label-tint-amber   { --label-fill: #fdeccb; --label-ink: #7c4a03; --label-edge: #b08034; }
.label-tint-green   { --label-fill: #dcf2df; --label-ink: #14532d; --label-edge: #5e9d71; }
.label-tint-blue    { --label-fill: #dbecfb; --label-ink: #14457a; --label-edge: #5b93c9; }
.label-tint-violet  { --label-fill: #e9e3fb; --label-ink: #4c2d8f; --label-edge: #8878cc; }
.label-tint-magenta { --label-fill: #fbe0f0; --label-ink: #86176b; --label-edge: #c2739f; }
.label-tint-teal    { --label-fill: #d9f0f2; --label-ink: #115e63; --label-edge: #4f9ea5; }
.label-tint-stone   { --label-fill: #eae7dd; --label-ink: #44403c; --label-edge: #94907f; }
.label-tint-copper  { --label-fill: #fae4d6; --label-ink: #8a3a12; --label-edge: #bc7c52; }
.label-tint-slate   { --label-fill: #e3e9f0; --label-ink: #334155; --label-edge: #7f8fa3; }

/*
 * A middle stamp, for a reveal with more teams on it than the roomy tier can hold.
 *
 * 6rem is what the letter wants when there are three teams and the screen is mostly empty. At
 * eight it is 768px of stamp on a 1080px projector before a word has been drawn, which is how the
 * last three teams ended up below the bottom of the screen. See DisplaysHelper#reveal_density.
 */
.grade-stamp-md {
  width: 4rem;
  height: 4rem;
  font-size: 2.25rem;
  border-width: 3px;
}

