/* Daily AI Sprints landing page.
   Tokens come from DESIGN.md (Solarized Native). Do not introduce a colour here
   that is not in that file, and do not give any colour its only definition
   inside a media query. */

/* ---------- Light palette: the base definition ---------- */
/* ---------- Fonts ----------
   Self-hosted from this origin, so a page that collects email addresses makes
   no third-party request. One variable WOFF2 per family, latin subset, weights
   200 to 800, SIL Open Font License 1.1; the licence text sits beside the files
   in assets/fonts/. swap: the fallback stack is legible on its own, so text
   shows at once and re-renders when the file lands. */
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("../assets/fonts/atkinson-hyperlegible-next-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Atkinson Hyperlegible Mono";
  src: url("../assets/fonts/atkinson-hyperlegible-mono-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  color-scheme: light;

  --canvas: #fdf6e3;
  --surface: #eee8d5;
  --card: #fdf6e3;
  --text: #073642;
  --muted: #4e6168;
  --border-ui: #657b83;
  --divider: #93a1a1;
  --link: #1a649e;
  --link-hover: #14507f;
  --link-visited: #6d3c9e;
  --cta: #cb4b16;
  --cta-hover: #b7420f;
  --on-cta: #ffffff;
  --accent-text: #9a370c;
  --focus: #1a649e;
  --error: #c0201f;
  --success: #4f6b00;

  /* The video-call pictures are drawn like a screenshot of a dark call
     window, so they keep the same two colours in both themes. White on this
     grey is 16.1:1. */
  --video-frame: #1b1b1b;
  --video-text: #f5f5f5;
  /* The "You are viewing" strip over a shared screen, the one green in the
     system, darkened until white on it is 6.0:1. */
  --share-bar: #0f6b3a;

  /* Brand mark, "outline" treatment: the face always matches the page, so the
     frame and hands are the only marks and the logo reads the same weight in
     both themes. The lockup is a closed two-colour system: --logo-line carries
     this block's --link, the blue of "AI Sprints", and --logo-accent carries
     --accent-text, the orange of "Daily". The hour hand that fixes the clock at
     8:00 is the only accented stroke. Nothing in the mark is body-text navy,
     because nothing in the wordmark is either. */
  --logo-face: #fdf6e3;
  --logo-line: #1a649e;
  --logo-accent: #9a370c;

  --font-body: "Atkinson Hyperlegible Next", "Atkinson Hyperlegible", system-ui,
    -apple-system, "Segoe UI", sans-serif;
  --font-eyebrow: "Atkinson Hyperlegible Mono", ui-monospace, SFMono-Regular,
    Consolas, monospace;

  --space-xs: 0.25rem;
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
  --space-xxl: 3rem;
  --space-section: 4rem;
  --space-hero: 4rem;

  --radius: 6px;
  --container-max: 1200px;
  --container-narrow: 800px;
  --reading-width: 68ch;
  --target-min: 44px;
}

/* System preference resolves to dark, unless the visitor explicitly chose light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --canvas: #002b36;
    --surface: #073642;
    --card: #0a3a47;
    --text: #eee8d5;
    --muted: #93a1a1;
    --border-ui: #839496;
    --divider: #586e75;
    --link: #6fb6ee;
    --link-hover: #9ccdf5;
    --link-visited: #c7a6e8;
    --cta: #f08a4b;
    --cta-hover: #f59b63;
    --on-cta: #002b36;
    --accent-text: #f59b63;
    --focus: #b58900;
    --error: #ff9c93;
    --success: #7dc77a;

    --video-frame: #1b1b1b;
    --video-text: #f5f5f5;
    --share-bar: #0f6b3a;

    --logo-face: #002b36;
    --logo-line: #6fb6ee;
    --logo-accent: #f59b63;
  }
}

/* Explicit dark choice wins regardless of the OS setting. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --canvas: #002b36;
  --surface: #073642;
  --card: #0a3a47;
  --text: #eee8d5;
  --muted: #93a1a1;
  --border-ui: #839496;
  --divider: #586e75;
  --link: #6fb6ee;
  --link-hover: #9ccdf5;
  --link-visited: #c7a6e8;
  --cta: #f08a4b;
  --cta-hover: #f59b63;
  --on-cta: #002b36;
  --accent-text: #f59b63;
  --focus: #b58900;
  --error: #ff9c93;
  --success: #7dc77a;

  --video-frame: #1b1b1b;
  --video-text: #f5f5f5;
  --share-bar: #0f6b3a;

  --logo-face: #002b36;
  --logo-line: #6fb6ee;
  --logo-accent: #f59b63;
}

/* ---------- Base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1.125rem;
  line-height: 1.55;
}

h1,
h2,
h3 {
  margin: 0;
  line-height: 1.2;
  text-wrap: balance;
}

h1 {
  font-size: 3.5rem;
}
h2 {
  font-size: 2rem;
}
h3 {
  font-size: 1.5rem;
  line-height: 1.25;
}

p {
  margin: 0;
  max-width: var(--reading-width);
}

/* Body links keep their underline in every state, including hover. */
a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

a:hover {
  color: var(--link-hover);
  text-decoration-thickness: 2px;
}

a:visited {
  color: var(--link-visited);
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* ---------- Layout ---------- */
.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

.band {
  padding-block: var(--space-section);
}

.band--tinted {
  background: var(--surface);
}

/* ---------- Visually hidden ----------
   One definition of the clip technique, for anything the eye does not need
   but assistive technology does. Not display:none and not visibility:hidden:
   either would take the element out of the accessibility tree along with the
   pixels, and would drop a focusable control out of the tab order.

   The theme radios are here for that second reason. They have to stay
   focusable, because their labels are the whole visible control.

   The word inside each theme label is here too. It names the radio, so it
   stays in the accessibility tree at every width, while the sun and moon
   carry the meaning to the eye. */
.visually-hidden,
.theme-choice input,
.theme-choice__word {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Skip link ---------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  background: var(--card);
  color: var(--link);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
  min-height: var(--target-min);
  display: inline-flex;
  align-items: center;
  font-weight: 600;
}

.skip-link:focus {
  left: var(--space-md);
  top: var(--space-md);
}

/* ---------- Header ---------- */
/* The header is a masthead, the way a daily paper opens: the lockup centred
   on its own row, then a ruled row holding the navigation and the theme
   control. Joe chose it on September 8, 2026 from ten drawn directions. The
   rule row carries a hairline above and below, so the header needs no
   bottom border of its own. Since September 9, 2026 the rule row sits on
   surface, Joe's choice from four rendered treatments, and the hero below it
   sits on canvas so the row does not run into it. */
.site-header {
  background: var(--canvas);
}

.site-header__mast {
  display: flex;
  justify-content: center;
  padding-block: var(--space-lg) var(--space-md);
}

.site-header__rule {
  background: var(--surface);
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
}

/* Three columns: the links centred in the middle one, the theme control at
   the end of the third, the first left empty so the links sit on the page's
   true centre rather than the centre of what the control leaves. */
.site-header__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  min-height: 52px;
}

/* The site navigation: a nav landmark holding four links, three into the
   landing page and one to the pricing page, set in the eyebrow face as spaced
   capitals so the row reads as a paper's section list. The list wraps rather
   than hiding behind a button: four short labels never need a disclosure
   menu. */
.site-nav {
  grid-column: 2;
}

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 var(--space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The one set of links in the system without a resting underline. The ruled
   row, the landmark, and the capitals say "navigation" on their own, and a row
   of underlined capitals reads as a row of rules. Hover brings the underline
   in with link-hover, so the affordance is a hover away. Each link carries
   the 44px target. Letter-spacing is in em so it scales with the size;
   DESIGN.md records the resulting pixel value. */
.site-nav-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
  padding: 0 var(--space-xs);
  color: var(--text);
  font-family: var(--font-eyebrow);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
}

/* No visited state on navigation. The same four links sit on every page, so
   after one trip through the site every one of them would be visited purple
   for good. A visited cue only carries meaning on content links a reader may
   or may not have followed. The footer's policy links get the same treatment. */
.site-nav-link:visited {
  color: var(--text);
}

.site-footer__links a:visited {
  color: var(--link);
}

.site-nav-link:hover {
  color: var(--link-hover);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.6em;
}

/* The link to the page being viewed: the wordmark's warm colour plus a 2px
   underline, so the cue does not rest on colour and survives forced-colors
   mode, where the underline is all that is left. It stays a link. Declared
   after the hover rule at equal specificity, so hover does not repaint it. */
.site-nav-link[aria-current="page"],
.site-nav-link[aria-current="page"]:visited,
.site-nav-link[aria-current="page"]:hover {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.6em;
}

/* The whole lockup is one link to home, so the mark and the words cannot be
   tabbed to separately. Centred in the masthead row; the text block keeps its
   own left edge so the tagline lines up under "Daily". The mark hangs from
   the top of the text block rather than centring on it, so its frame can be
   pinned to the type's ink (see .dais-mark); centring put its bottom 3.4px
   short of the dateline baseline. */
.brand {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.brand:hover,
.brand:visited {
  color: inherit;
  text-decoration: none;
}

.brand-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
}

/* The wordmark at display size, the one type size between h2 and h1. A
   masthead name is the largest type on the page after the h1; at 1.5rem it
   read as a form label beside the navigation. */
.brand-name {
  font-size: 2.75rem;
  font-weight: 700;
  line-height: 1.1;
  white-space: nowrap;
}

/* Two-tone wordmark, the same split Rapid AI Sprints uses: warm on the first
   word, cool on the rest, and neither is body text. Borrowing the link colour
   for "AI Sprints" is safe here only because the entire lockup is itself a
   link to home, so it cannot mislead anyone about what is clickable.
   Light 6.65:1 and 5.79:1, dark 6.97:1 and 6.86:1. */
.brand-name-accent {
  color: var(--accent-text);
}

.brand-name-cool {
  color: var(--link);
}

/* The tagline as a paper's dateline: the eyebrow face in spaced capitals,
   tracked wider than the eyebrow because it stands alone under the name. */
.brand-tagline {
  font-family: var(--font-eyebrow);
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The mark carries no fill of its own. Three tokens colour it, which is the
   whole reason one file serves both themes.

   Sized to the lockup the way the headlines mark is sized to its question:
   the frame's outer edge runs from the cap line of "Daily" to the dateline's
   baseline, so the mark and the two lines of type share both edges. At the
   display size (2.75rem, line-height 1.1) over the 0.8125rem dateline
   (line-height 1.4) with the 0.25rem gap between them, that span is 56.8px,
   and the frame's outer edge is 8/512 of the box in from each end (the rect
   at 24 minus half its 32 stroke). That gives a 3.663rem box pushed down
   0.481rem from the top of the text block. The two narrower steps below
   re-derive both numbers for their own sizes. Change the display, tagline
   or gap values and re-measure; the numbers were checked against the
   rendered page at 1280, 700 and 400px on September 10, 2026. */
.dais-mark {
  width: 3.663rem;
  height: 3.663rem;
  margin-top: 0.481rem;
  flex: none;
}

.dais-mark__face {
  fill: var(--logo-face);
  stroke: var(--logo-line);
}

.dais-mark__hand {
  stroke: var(--logo-line);
  stroke-linecap: round;
}

/* The hour hand is the only accented stroke. It is what says 8:00 rather than
   leaving the face a generic clock, so it is the part worth colouring.
   Declared after .dais-mark__hand: same specificity, so source order wins. */
.dais-mark__hand--hour {
  stroke: var(--logo-accent);
}

/* The "now" marker, added by script (see index.html): a dot on the inside of
   the frame at the visitor's local hour. Muted because it is decoration and
   carries nothing a visitor needs, so it is exempt from contrast. Between
   08:00 and 08:45, while the sprint is live, it takes the accent so the mark
   reads "8, and it is 8 now". The two states are the only ones there are. */
.dais-mark__now {
  fill: var(--muted);
}

.dais-mark__now--live {
  fill: var(--logo-accent);
}

/* Two icon chips side by side at the end of the rule row: the live one filled
   in link, the other outlined in border-ui, both at the 6px radius the rest of
   the page uses. Tailwind, HeroUI and fumadocs all draw this control as a
   pill, and DESIGN.md rules pill shapes out: the squarer geometry is part of
   what makes the page read as Solarized.

   Until September 8, 2026 the two options sat on a surface track with their
   words showing, and that made the control the heaviest object in the header,
   ahead of the navigation it sat beside. Both options are still on screen and
   the live one is still filled in, which is the whole point of the shape.

   position: relative contains the absolutely positioned legend and radios.
   The surface background matches the rule row the control sits in and is
   declared so the design gate can read it. */
.theme-choice {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--surface);
  grid-column: 3;
  justify-self: end;
}

/* The radios themselves are clipped by the visually-hidden rule above.
   The label is the whole target, so it carries the 44px minimum rather than
   the 1px input it names. The outline is border-ui, not divider: an
   unselected option is still a control, and SC 1.4.11 wants its edge at 3:1. */
.theme-choice label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--target-min);
  min-height: var(--target-min);
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
}

.theme-choice svg {
  width: 20px;
  height: 20px;
  flex: none;
  stroke-width: 1.9;
}

/* The live option takes the link blue as a solid fill, with its icon on
   canvas. SC 1.4.11 asks 3:1 of a control carrying state; DESIGN.md holds the
   measured ratios against the header.

   The fill is a hue on purpose. Marking this particular control with a tone
   backfires, because tone is the subject: filling the live option with text
   makes a dark block mark "Light" in the light theme and a bright block mark
   "Dark" in the dark one, so the colour contradicts the option it sits on.
   Blue belongs to neither theme, so it can only mean "this one is on". It is
   blue rather than the warm accent because the header must not carry the
   loudest colour on the page; that belongs to the hero's call to action.

   The tonal chip that Tailwind, HeroUI and fumadocs use is a canvas-on-surface
   step, 1.14:1 here, and a tonal step is not a boundary. Four cues stack in
   this version, fill, outline, position and stroke weight, so nothing rests
   on colour alone and it survives a blurred glance. */
.theme-choice input:checked + label {
  background: var(--link);
  border-color: var(--link);
  color: var(--canvas);
}

.theme-choice input:checked + label svg {
  stroke-width: 2.4;
}

/* The input is clipped to a pixel, so the outline has to be drawn on the
   label the visitor is actually looking at. */
.theme-choice input:focus-visible + label {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* ---------- Hero ---------- */
/* Canvas since September 9, 2026: the header's rule row took surface, and a
   surface hero would run into it. Every band below flipped with it. */
.hero {
  background: var(--canvas);
  padding-block: var(--space-hero);
}

.hero-eyebrow {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--space-sm);
}

.hero h1 {
  line-height: 1.1;
}

/* A class, not ".hero p": the eyebrow is also a paragraph in the hero, and
   so is every step in the rail. */
.hero-lede {
  font-size: 1.1875rem;
  line-height: 1.7;
  color: var(--muted);
  margin-block: var(--space-sm) var(--space-lg);
}

.hero-layout {
  display: grid;
  gap: var(--space-xl);
  align-items: start;
}

/* Top-aligned, not centred: the copy block is shorter than the rail, and
   centring it left the headline floating in the middle of the band with the
   eyebrow's cap line meeting nothing. Now it meets the rail's top edge. */
@media (min-width: 1000px) {
  .hero-layout {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: var(--space-hero);
    align-items: start;
  }
}

/* The rail explains the core session rather than introducing another offer.
   border-ui on the edge, like every card. Since the hero moved to canvas on
   September 9, 2026 the card fill matches the band in light and steps 1.22:1
   in dark, so the edge is what a reader with low vision uses to see what
   belongs together. The input is told apart from cards by weight, not by
   tone. */
.session-rail {
  background: var(--card);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-lg);
}

.session-rail__title {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--space-sm);
}

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

.session-rail__list li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-md);
  padding-block: calc(var(--space-lg) / 2);
  border-top: 1px solid var(--divider);
}

.session-rail__list li:last-child {
  padding-bottom: 0;
}

.session-rail__list h3 {
  font-size: 1.125rem;
  margin-bottom: var(--space-xs);
}

.session-rail__list p {
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
  margin: 0;
}

.session-rail__num {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}

/* ---------- Actions ---------- */
.action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--target-min);
  padding: var(--space-sm) var(--space-lg);
  background: var(--cta);
  color: var(--on-cta);
  border: 0;
  border-radius: var(--radius);
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
}

.action:hover,
.action:visited {
  background: var(--cta-hover);
  color: var(--on-cta);
  text-decoration: none;
}

/* The hero's action is the one the page exists for, so it gets a larger label
   and a taller target than the card actions. */
.hero .action {
  min-height: 52px;
  padding: var(--space-md) var(--space-xl);
  font-size: 1.0625rem;
}

/* The outlined secondary action that the two organization cards carried was
   retired September 4, 2026 at Joe's direction: every offer action is the
   solid orange now. */

/* ---------- Membership ---------- */
.membership-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg);
  margin-block: var(--space-lg) var(--space-md);
  padding: 0;
  list-style: none;
}

/* Each card is a flex column so actions align within each grid row even when
   the offer descriptions have different lengths. */
.membership-card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-lg);
}

.membership-card p {
  color: var(--muted);
  margin-block: var(--space-sm);
}

/* On /pricing/ the card name is an h2 under the page's h1, drawn at the h3
   size the cards were designed at. */
.membership-card__name {
  font-size: 1.5rem;
  line-height: 1.25;
}

.membership-card__kicker {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin: 0 0 var(--space-xs);
}

/* Scoped to the card on purpose. A bare .price loses to the .membership-card p
   rule above, which is one class plus an element and therefore more specific,
   so the price rendered in muted grey rather than accent for as long as both
   rules have existed. The design-system gate caught it; no human review did. */
.membership-card .price {
  color: var(--accent-text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  margin-block: var(--space-sm) var(--space-lg);
}

.membership-card .action {
  margin-top: auto;
  align-self: flex-start;
}

.terms {
  color: var(--muted);
  font-size: 0.9375rem;
}

/* What the money actually buys. Approved 2026-08-16, and it has to sit above
   the checkout link rather than below it. */
.access-terms {
  color: var(--muted);
  font-size: 0.9375rem;
  margin-block: 0 var(--space-lg);
}

/* ---------- Questions ---------- */
.faq-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg) var(--space-xxl);
  margin-top: var(--space-lg);
}

.faq-grid > div {
  border-top: 1px solid var(--divider);
  padding-top: var(--space-md);
}

.faq-grid h3 {
  font-size: 1.125rem;
  margin-bottom: var(--space-xs);
}

.faq-grid p {
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

/* ---------- Team ---------- */
.section-intro {
  color: var(--muted);
  margin-block: var(--space-sm) var(--space-xl);
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--space-lg);
  padding: 0;
  list-style: none;
}

/* card on the team band's surface. Until September 9, 2026 the band was
   canvas and the cards surface; the ground flip swapped both. */
.bio-card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-lg);
}

/* Photo beside name and credential, all left-aligned, so the card reads as one
   layout top to bottom. */
.bio-card__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
}

/* Below about 14rem of remaining width the text drops under the photo instead
   of wrapping into a six-line column beside it. */
.bio-card__header > div {
  flex: 1 1 14rem;
  min-width: 0;
}

.bio-photo {
  width: 96px;
  height: 96px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--divider);
}

.bio-card h3 {
  margin: 0;
}

/* Muted, not accent: the one warm colour on this page belongs to prices and
   the wordmark, and a job title is not a call to action. */
.bio-role {
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.5;
  margin-block: var(--space-xs) 0;
  max-width: none;
}

/* A left rule, not a background tint: the step from card to surface is about
   1.15:1 and would not read as a boundary on its own. */
.bio-quote {
  margin: 0 0 var(--space-lg);
  padding-left: var(--space-md);
  border-left: 3px solid var(--divider);
  font-style: italic;
}

.bio-quote p {
  color: var(--text);
}

/* A standalone link, not one inside a sentence, so it carries the full 44px
   target the system promises rather than the inline-link exemption. */
.bio-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
  margin-top: auto;
  align-self: flex-start;
  font-weight: 600;
}

/* ---------- Newsletter ----------
   Lives in the footer. A small opt-in beside the legal lines, the way most
   sites keep one, rather than a band of its own competing with the offers. */
.newsletter-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  max-width: 30rem;
}

.newsletter-form__title {
  font-size: 1.125rem;
  margin: 0 0 var(--space-xs);
}

.newsletter-form label {
  font-size: 0.9375rem;
  font-weight: 600;
}

.field-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

input[type="email"] {
  flex: 1 1 16rem;
  min-height: var(--target-min);
  padding: var(--space-sm);
  font-family: inherit;
  font-size: 1.125rem;
  color: var(--text);
  background: var(--card);
  /* 2px, where cards carry 1px: the one input on the page is told apart from
     the cards around it by weight, so both can share the border-ui tone. */
  border: 2px solid var(--border-ui);
  border-radius: var(--radius);
}

input[type="email"][aria-invalid="true"] {
  border-width: 2px;
  border-color: var(--error);
}

.field-hint {
  color: var(--muted);
  font-size: 0.9375rem;
}

.field-error {
  color: var(--error);
  font-size: 0.9375rem;
  font-weight: 600;
}

.field-error:empty {
  display: none;
}

.form-status {
  color: var(--success);
  font-weight: 600;
}

.form-status:empty {
  display: none;
}

.consent {
  color: var(--muted);
  font-size: 0.9375rem;
}

/* ---------- Contact request form ----------
   On the enterprise contact page, under the offer card, since dais-2gw. The same
   controls as the AI Briefings input, stacked in one column with a textarea.
   The global input[type="email"] rule above carries a 16rem flex-basis meant
   for the footer's field-row; inside this column that basis would become a
   16rem height, so every control here resets it. */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 36rem;
  margin-top: var(--space-xl);
}

/* An h2 drawn at the card-name size, the way /pricing/ draws its card names. */
.contact-form__title {
  font-size: 1.5rem;
  line-height: 1.25;
}

.contact-form .field {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.contact-form label {
  font-size: 0.9375rem;
  font-weight: 600;
}

.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form textarea {
  flex: none;
  width: 100%;
  min-height: var(--target-min);
  padding: var(--space-sm);
  font-family: inherit;
  font-size: 1.125rem;
  /* Form controls do not inherit line-height. Set body's 1.55 here so these
     controls match the body style DESIGN.md names for them, instead of
     joining the text-input drift recorded under dais-wio. */
  line-height: 1.55;
  color: var(--text);
  background: var(--card);
  border: 2px solid var(--border-ui);
  border-radius: var(--radius);
}

.contact-form textarea {
  min-height: 8rem;
  resize: vertical;
}

.contact-form input[aria-invalid="true"],
.contact-form textarea[aria-invalid="true"] {
  border-color: var(--error);
}

.contact-form .action {
  align-self: flex-start;
}

.checkout-form {
  margin-top: var(--space-lg);
}

/* ---------- Footer ----------
   Surface, so the bands keep alternating all the way down: hero tinted,
   the four live-hour bands canvas first, team canvas, questions canvas
   behind a rule, footer tinted. Two adjacent bands of the same tone read as
   one section, which is why the questions band carries a rule now that the
   membership band has moved to /pricing/. The border remains because the
   tonal step is only about 1.14:1 and is not a boundary on its own. */
.site-footer {
  background: var(--surface);
  border-top: 1px solid var(--divider);
  padding-block: var(--space-xl);
}

.site-footer__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
  gap: var(--space-xl) var(--space-xxl);
  align-items: start;
}

.site-footer p {
  color: var(--muted);
  font-size: 0.9375rem;
  margin-block: var(--space-xs);
}

/* Each footer link stands alone on its line, so it gets the full target. The
   consent line's privacy link is inline in a sentence and keeps the
   exemption. */
.site-footer__meta a {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
}

/* The policy links: a plain list under the copyright lines, not a nav
   landmark, so the header navigation stays the only one on the page. Body
   links at body-small size; the muted copyright lines above them are label
   size, and one step up keeps the links readable as links. */
.site-footer__links {
  margin: var(--space-sm) 0 0;
  padding: 0;
  list-style: none;
}

.site-footer__links a {
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
}

/* ---------- Live-hour sections ----------
   Five bands, one per stage of the rail, alternating surface, canvas,
   surface, canvas, surface since the ground flip of September 9, 2026.
   Shared pieces first, then one block per section. Image sources and
   permissions are in assets/live-hour/CREDITS.md. */

/* The rail numeral, repeated as the section's step. Same style as the rail. */
.step-num {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
  margin: 0 0 var(--space-sm);
}

/* Short mono labels inside the sections: guest labels, the screen-share
   bar. The hero eyebrow, in a different colour context. */
.eyebrow {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

/* Captions and small notes, at the body-small size. */
.figure-note {
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

figcaption.figure-note {
  margin-top: var(--space-md);
}

/* Photographs sit at the card's radius with a border-ui edge, like every
   other object whose edge must be seen against a tonal step. */
.portrait__photo,
.tile__photo {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
}

/* Square by contract (dais-yci): every guest supplies or is given a square
   portrait of at least 800px, so the block never crops a photo it does not
   control. */
.portrait__photo {
  aspect-ratio: 1 / 1;
}

.tile__photo {
  position: absolute;
  inset: 0;
  height: 100%;
  border: 0;
  border-radius: 0;
}

.portrait,
.room,
.stage {
  margin: 0;
}

/* 01 AI Headlines: the rail question as the display line beside a headlines
   mark drawn in the brand clock's language (same frame, same stroke, same two
   colours, a headline stroke over two columns of text strokes inside), and
   Joe's paragraph as the answer behind an accent rule. The section name drops to h4 size so the question
   leads.

   The row shares one top edge, and the mark is sized to the two-line
   question so the two read as one object: its outer frame runs from the cap
   height of the first line to the baseline of the second. At the display
   size (2.75rem, line-height 1.1) the face's cap top sits 9.3px below the
   line box and the second baseline 87.1px below it, and the frame's outer
   edge is 8/512 of the box in from each end (the rect at 24 minus half its
   32 stroke). That gives a 5.02rem box pushed down 0.46rem, both checked
   against the rendered page. Change the display token and re-derive both
   numbers. Until September 10, 2026 the frame stroke was 24, the inset
   12/512, and the box 5.1rem; the strokes went up with the brand mark's
   (Joe's 1C). The question column takes three parts to the paragraph's two,
   which keeps the question on two lines from 940px up. */
.headlines__heading {
  font-size: 1.125rem;
  line-height: 1.25;
  margin: 0 0 var(--space-xl);
}

.headlines {
  display: grid;
  grid-template-columns: 5.02rem minmax(0, 3fr) minmax(0, 2fr);
  gap: var(--space-xl);
  align-items: start;
}

.headlines__mark {
  width: 5.02rem;
  height: 5.02rem;
  margin-top: 0.46rem;
  display: block;
}

.headlines__mark-face {
  fill: var(--surface);
  stroke: var(--link);
}

/* The strokes take the logo's line colour, not body-text navy, so the mark is
   one blue object with one rust stroke, exactly what the clock is. */
.headlines__mark-line {
  stroke: var(--logo-line);
  stroke-linecap: round;
}

.headlines__mark-line--lead {
  stroke: var(--accent-text);
}

.headlines__question {
  margin: 0;
  font-size: 2.75rem;
  line-height: 1.1;
  font-weight: 700;
  color: var(--text);
  text-wrap: balance;
}

.headlines__answer {
  margin: 0;
  color: var(--muted);
  font-size: 1.125rem;
  line-height: 1.55;
  border-left: 3px solid var(--accent-text);
  padding-left: var(--space-lg);
}

/* 02 Guest of the Day */
.guest {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--space-xxl);
  align-items: start;
}

.guest-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.guest-card__name {
  font-size: 2rem;
  line-height: 1.2;
}

.guest-card__line {
  color: var(--muted);
}

.technique {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  border-top: 1px solid var(--divider);
  padding-top: var(--space-md);
}

/* The base reset covers h1 to h3; h4 keeps the browser's 1.33em margins
   unless a component clears them. */
.technique h4 {
  margin: 0;
  font-size: 1.5rem;
  line-height: 1.25;
}

/* 03 Group Check-In: the room and the three things members discuss. */
.checkin {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--space-xxl);
  align-items: start;
}

/* The video-call frame. A dark window with square tiles in a three-by-two
   grid, the way a gallery view looks, drawn in the two video tokens so it
   stays a dark window in both themes. The frame's own edge is border-ui so
   it reads against the band like every other object. */
.room__frame {
  background: var(--video-frame);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-sm);
}

.room__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.tile {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--video-frame);
  border: 1px solid var(--video-frame);
  border-radius: calc(var(--radius) - 2px);
  color: var(--video-text);
}

/* Weight, not colour, marks the speaker: a 3px light edge where the others
   have none, and the label says it in words. */
.tile--speaking {
  border: 3px solid var(--video-text);
}

/* The name strip every call draws in the bottom-left corner, and the status
   chip in the top-left. Both are the frame colour with the frame's text,
   16.1:1, and never colour alone: the mic and hand icons sit beside words. */
.tile__name,
.tile__status {
  position: absolute;
  left: 6px;
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  max-width: calc(100% - 12px);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--video-text);
  background: var(--video-frame);
  border-radius: 3px;
  padding: 0.15em 0.5em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tile__name {
  bottom: 6px;
}

.tile__status {
  top: 6px;
}

.tile__name svg,
.tile__status svg {
  width: 14px;
  height: 14px;
  flex: none;
}

.compare {
  margin: var(--space-md) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--divider);
}

.compare li {
  padding-block: var(--space-md);
  border-bottom: 1px solid var(--divider);
}

.compare h4 {
  margin: 0 0 var(--space-xs);
}

.compare p {
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

/* 04 The Sprint: two halves under one banner, each opening with a rule, a
   heading, and one sentence. The first half is the ballot, the second the
   screen share. */
.sprint-part {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--divider);
}

.sprint-part h3 {
  margin-bottom: var(--space-xs);
}

/* The ballot and its spotlight, Joe's choice of September 4, 2026: the four
   rows down the left, and the voted challenge repeated large in a card on
   the right, so the half is balanced and the outcome is unmissable. The list
   has no closing rule of its own, because the next half opens with one and
   two rules a breath apart read as a mistake. */
.ballot-wrap {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--space-xxl);
  align-items: start;
}

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

.ballot li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-md);
  align-items: start;
  padding: var(--space-md) var(--space-sm);
  border-top: 1px solid var(--divider);
}

.ballot__mark {
  width: 24px;
  height: 24px;
  flex: none;
  margin-top: 2px;
  color: var(--border-ui);
}

/* Category over the challenge, so the rows read at the list's width. */
.ballot__body {
  display: grid;
  gap: var(--space-xs);
}

.ballot__cat {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: 0.3rem;
}

.ballot__status {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-text);
  white-space: nowrap;
  padding-top: 0.3rem;
}

/* The voted row: filled check and bold text in the list; the card and the
   words live in the spotlight beside it. Never colour alone. */
.ballot li.is-chosen .ballot__mark {
  color: var(--accent-text);
}

.ballot__mark-check {
  stroke: var(--canvas);
}

.ballot li.is-chosen .ballot__text {
  font-weight: 700;
}

.spotlight {
  display: grid;
  gap: var(--space-sm);
  background: var(--card);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-lg);
}

.spotlight__mark {
  width: 32px;
  height: 32px;
  margin: 0;
  color: var(--accent-text);
}

.spotlight .ballot__status {
  padding-top: 0;
}

.spotlight__cat {
  font-family: var(--font-eyebrow);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: var(--space-sm) 0 0;
}

.spotlight__text {
  font-size: 1.5rem;
  line-height: 1.25;
  font-weight: 700;
  margin: 0;
}

/* The Sprint's second half: the screen share and the people beside it. */
.stage__layout {
  display: grid;
  grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
  gap: var(--space-lg);
  align-items: stretch;
}

/* The shared screen, drawn the way a call draws one: the same dark frame as
   the tiles, the "You are viewing" bar a call lays across the top, and the
   shared app window inside. No fixed ratio: it stretches to the height of
   the tile column beside it, which is what a shared screen does when the
   gallery is taller. */
.share {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  background: var(--video-frame);
  color: var(--video-text);
  border: 1px solid var(--border-ui);
  border-radius: var(--radius);
  padding: var(--space-sm);
}

/* The one place share-bar appears. Same in both themes, like the frame,
   because the picture is a screenshot. */
.share__bar {
  margin: 0;
  max-width: none;
  text-align: center;
  background: var(--share-bar);
  color: var(--video-text);
  border-radius: 4px;
  padding: 0.35rem var(--space-md);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
}

.share__window {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  min-height: 22rem;
  background: var(--card);
  color: var(--text);
  border-radius: 4px;
  padding: var(--space-md) var(--space-lg) var(--space-lg);
}

/* Window chrome: three dots and nothing else, so it reads as an app window
   without naming one. */
.share__titlebar {
  display: flex;
  gap: 6px;
  margin-bottom: var(--space-xs);
}

.share__titlebar span {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--divider);
}

.turn {
  max-width: 80%;
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
  font-size: 1rem;
  line-height: 1.5;
}

.turn--member {
  align-self: flex-end;
  background: var(--surface);
  border: 1px solid var(--divider);
  color: var(--text);
}

.turn--ai {
  align-self: flex-start;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  width: 80%;
  border: 1px dashed var(--border-ui);
  color: var(--muted);
}

.turn--ai p {
  color: var(--muted);
}

.turn__list {
  margin: 0;
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  color: var(--text);
}

/* Two columns of square tiles in the same dark frame as the breakout room,
   the gallery strip a call shows beside a shared screen. */
.people {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.tile__photo {
  object-position: 50% 30%;
}

.leave {
  margin-top: var(--space-xl);
  color: var(--muted);
}

@media (max-width: 760px) {
  /* minmax(0, 1fr), not 1fr: a bare 1fr is minmax(auto, 1fr), and a wide
     child would hold the column open past 320px. */
  .guest,
  .checkin,
  .stage__layout {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
  }

  .ballot-wrap,
  .headlines {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
  }

  .headlines__mark {
    width: 5rem;
    height: 5rem;
    margin-top: 0;
  }

  .headlines__question {
    font-size: 2rem;
  }

  .guest-card__name {
    font-size: 1.625rem;
  }

  /* Two columns of square tiles. At 320px each tile is about 140px, which
     still holds a name strip over the photograph. */
  .room__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ballot__cat,
  .ballot__status {
    padding-top: 0;
  }

  .ballot__status {
    white-space: normal;
  }

  .share__window {
    min-height: 0;
  }

  .turn {
    max-width: 100%;
  }

  .turn--ai {
    width: 100%;
  }

  /* Under the screen the strip keeps two columns, the same shape as the
     breakout room above it. Three columns at 320px cut the name strips. */
  .people {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- Responsive ---------- */

/* The masthead stays centred at every width. Below 760px the rule row stops
   centring its links: they take the left edge and wrap to two lines, the
   theme control keeps the right edge, and the wordmark and mark step down so
   the lockup fits a phone. Same DOM order as the wide layout, so the tab order
   never differs from what is on screen. The list wraps onto a third line only
   when the viewport forces it; nothing hides behind a button. */
@media (max-width: 760px) {
  .site-header__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs) var(--space-md);
    padding-block: var(--space-xs);
  }
  /* flex-basis 0, not auto: with auto the list's one-line width is the
     basis, wider than the row, so the nav took a row of its own and pushed
     the theme control to a second. With 0 it takes what the theme control
     leaves and wraps its links inside that. */
  .site-nav {
    flex: 1 1 0;
    min-width: 0;
  }
  .site-nav__list {
    justify-content: flex-start;
    gap: 0 var(--space-md);
    /* The links' 4px side padding would set their letters 4px inside the
       edge the hero text sits on. Pull the list back so the letters share it. */
    margin-inline-start: calc(-1 * var(--space-xs));
  }
  .theme-choice label {
    min-width: 48px;
  }
  .brand-name {
    font-size: 2.25rem;
  }
  /* Cap line to dateline baseline is 49.6px at 2.25rem over the 13px
     dateline; box and offset re-derived as for the wide size. */
  .dais-mark {
    width: 3.203rem;
    height: 3.203rem;
    margin-top: 0.39rem;
  }
}

@media (max-width: 480px) {
  .brand {
    gap: var(--space-sm);
  }
  .brand-name {
    font-size: 1.625rem;
  }
  /* The dateline has to end inside the name. At 1.625rem the name is about
     193px wide and the 13px tagline about 222px, so it steps down too. */
  .brand-tagline {
    font-size: 0.75rem;
    letter-spacing: 0.12em;
  }
  /* Cap line to dateline baseline is 39px at 1.625rem over the 12px
     dateline; box and offset re-derived as for the wide size. */
  .dais-mark {
    width: 2.514rem;
    height: 2.514rem;
    margin-top: 0.3125rem;
  }
}

@media (max-width: 760px) {
  h1 {
    font-size: 2.25rem;
  }
  h2 {
    font-size: 1.625rem;
  }
  .hero {
    padding-block: var(--space-xxl);
  }
  .band {
    padding-block: var(--space-xl);
  }
  .membership-grid {
    grid-template-columns: 1fr;
  }
  .faq-grid,
  .site-footer__layout {
    grid-template-columns: 1fr;
  }
  .field-row {
    flex-direction: column;
  }
  /* The 16rem flex-basis above is a width. In a column it would become a
     height, and the field rendered 256px tall. */
  input[type="email"] {
    flex-basis: auto;
  }
  .action,
  .theme-choice label,
  input[type="email"],
  .contact-form input[type="text"] {
    min-height: 48px;
  }
  .team-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------- Motion ----------
   Hover transitions only. A theme change must repaint instantly: cross-fading
   the whole page reads as a smear, and it also leaves the page in a half-applied
   palette that automated contrast checks will sample and fail on. The
   theme-switching class is added for one frame while the palette swaps. */
@media (prefers-reduced-motion: no-preference) {
  a,
  .action {
    transition: background-color 150ms ease-out, color 150ms ease-out;
  }
}

:root.theme-switching *,
:root.theme-switching *::before,
:root.theme-switching *::after {
  transition: none !important;
}

/* ---------- Forced colors ----------
   Preserve system colours rather than simulating Solarized. Backgrounds are
   dropped in this mode, so the action fill and the input border need explicit
   boundaries to stay perceivable. */
@media (forced-colors: active) {
  .action {
    border: 1px solid ButtonText;
    background: ButtonFace;
    color: ButtonText;
    forced-color-adjust: none;
  }

  .action:hover {
    background: Highlight;
    color: HighlightText;
  }

  .membership-card,
  .bio-card,
  .session-rail,
  .theme-choice label,
  input[type="email"],
  .contact-form input[type="text"],
  .contact-form textarea {
    border: 1px solid CanvasText;
  }

  /* The live-hour sections fill the chosen check with a solid, and forced
     colours drop fills, so it falls back to CanvasText on Canvas to stay
     visible. The video frames lose their dark fill, so the tiles and strips
     take a CanvasText edge to keep their shape. */
  .room__frame,
  .tile,
  .tile__name,
  .tile__status,
  .share,
  .share__bar,
  .share__window {
    border: 1px solid CanvasText;
  }

  .ballot li.is-chosen .ballot__mark {
    color: CanvasText;
  }

  .ballot__mark-check {
    stroke: Canvas;
  }

  .skeleton span {
    border: 1px solid GrayText;
  }

  /* The inverted chip has nothing to invert once backgrounds are dropped, and
     the radios themselves are clipped, so without this the live option would
     be unmarked. Highlight and HighlightText are the system's own "this one
     is selected" pair, which is why they are worth opting back in for. */
  .theme-choice input:checked + label {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }

  /* Backgrounds are dropped here, so the mark has to fall back to system
     colours or it disappears into the page. */
  .dais-mark__face {
    fill: Canvas;
    stroke: CanvasText;
  }

  /* --hour is named explicitly rather than left to source order, so the accent
     hand cannot survive into a mode that has dropped the palette. The 8:00
     still reads because the hour hand is the thicker of the two. */
  .dais-mark__hand,
  .dais-mark__hand--hour {
    stroke: CanvasText;
  }

  /* GrayText is the system's own "secondary" tone, which is what muted means.
     The live state loses its accent like the hour hand does, and still reads
     because the live dot is larger. */
  .dais-mark__now {
    fill: GrayText;
  }

  .dais-mark__now--live {
    fill: CanvasText;
  }

  :focus-visible {
    outline: 3px solid Highlight;
  }
}
