/* =========================================================================
   Super — site stylesheet
   =========================================================================

   Design language: Apple's marketing-page vocabulary.

     - One idea per screen, centred, with a lot of air around it.
     - Display type set large, semibold (600), with negative tracking. Never
       heavier: Apple gets emphasis from size, not from weight.
     - Full-bleed sections alternating near-white and true black.
     - Chrome is thin and quiet. The product is the only loud thing.
     - Calls to action are a blue pill and a blue "Learn more" chevron link,
       not a wall of buttons.
     - Small print sits at the bottom in grey, numbered.

   Held against that, two rules from the app's own design language survive
   unchanged, because SuperAAC is a communication aid before it is a product:

     1. Contrast is a floor. Body text clears 4.5:1, large text 3:1.
     2. Targets stay at 44px minimum even where Apple would go smaller, and
        motion is removed entirely under prefers-reduced-motion.
   ========================================================================= */

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

   TWO THEMES (owner, 2026-10-19: a dark/light switch, dark by default).

   assets/js/theme.js sets <html data-theme="dark|light"> before the first
   paint. The bare :root below is the DARK theme, so a page with no attribute
   at all -- JavaScript off -- is dark too. :root[data-theme="light"] restores
   the light site exactly as it was before the switch. It is written with
   :where() so it adds no specificity: a page that redefines a token on its
   own :root still wins in both themes, the same as it always has.

   Every colour a rule here uses is one of these tokens, so a rule never has
   to know which theme it is in. The dark column is the site's own dark
   design, the former black "Stage" bands (.band-dark): black ground, #1d1d1f
   surfaces, light ink, the bright blue.

   Names for other stylesheets (suite.css, the pages' own <style>):

     token             what it is for                             dark      light
     --paper           ground: page, every band, footer           #000000   #ffffff
     --paper-2         grey surface ON the ground: tiles, slots,  #1d1d1f   #f5f5f7
                       trays, panels
     --card            the white card of light mode: plans,       #1d1d1f   #ffffff
                       account / product / specialist / booking
                       cards, the floating symbol switch. A card
                       fill is --card, never --white, which stays
                       white in both themes.
     --raised          a fill ON a card: notes, avatars, tags,    #2c2c2e   #f5f5f7
                       state pills, a hovered white control
     --field           form fields and choice chips               #2c2c2e   #ffffff
     --rule            hairline: card edges, band and footer      #424245   #d2d2d7
                       edges
     --hairline        divider between rows (spec rows, footer)   w .16     k .11
     --hairline-2      softer divider (form sections)             w .12     k .08
     --dashed          dashed placeholder edge (.slot, .pending)  w .26     k .24
     --control-line    outline of fields and chips (3:1 in dark)  #86868b   #c7c7cc
     --wash            tint under the pointer on a clear control  w .08     k .045
     --wash-strong     the same, pressed                          w .14     k .08
     --track           empty part of a progress bar               w .16     k .10
     --ink             text                                       #f5f5f7   #1d1d1f
     --ink-2           secondary text                             #a1a1a6   #6e6e73
     --ink-strong      deepest ink (a pressed dark control)       #ffffff   #000000
     --ink-hover       an --ink fill under the pointer            #d2d2d7   #3a3a3c
     --blue            accent: links, focus ring, selected        #2997ff   #0071e3
     --blue-hover      accent fill under the pointer              #4aa7ff   #0077ed
     --blue-surface    a link on --paper-2 / --card               #2997ff   #0066cc
     --blue-wash       hover tint of a secondary (outline) button blue .14 blue .08
     --on-blue         text and icons on an accent fill           #00224d   #ffffff
     --error           error text, refused-field outline          #ff6961   #b3261e
     --danger          a destructive action's label               #ff6961   #d93025
     --ok-bg/-ink      a "done" state pill                        #203a28 / #30d158
     --bad-bg/-ink     a "cancelled" state pill                   #41292a / #ff8a84
     --info-bg/-ink    an informational tag or notice             #1f3347 / #6cb6ff
     --shadow-*        shadows (dark ones go deeper: on black a
                       soft shadow is invisible)
     --nav-*           the global bar's tray, current-page
                       capsule and phone menu (see .globalnav)

   Unchanged in both themes, because they name a fixed colour rather than a
   role: --white, --black, --ink-d, --ink-d2 and --blue-dark (the "on black"
   values .band-dark uses), and the board demo's --g-* app hues.

   Contrast, dark (measured): --ink on --paper 19.3, on --card 15.5; --ink-2
   on --paper 8.2, on --card 6.5, on --raised 5.4; --blue on --paper 7.0, on
   --card 5.6, on --raised 4.6; --on-blue on --blue 5.2, on --blue-hover 6.2;
   --control-line on --field 3.9, on --card 4.7; --error on --card 6.0;
   --ok-ink 6.1, --bad-ink 5.9 and --info-ink 6.0 on their own pills. */

:root {
  color-scheme: dark;
  /* Checkboxes and radios in the theme's accent, not the browser's own. */
  accent-color: var(--blue);

  /* Fixed colours (both themes) */
  --white: #ffffff;
  --black: #000000;
  --ink-d: #f5f5f7; /* ink on black */
  --ink-d2: #a1a1a6; /* 9.0:1 on black */
  --blue-dark: #2997ff; /* 7.4:1 on black */

  /* Grounds and surfaces */
  --paper: #000000;
  --paper-2: #1d1d1f;
  --card: #1d1d1f;
  --raised: #2c2c2e;
  --field: #2c2c2e;
  --seg-on: #636366; /* the chosen half of a two-way switch, on --paper-2 */
  --card-quiet: #000000; /* a card whose state could not be read */

  /* Lines */
  --rule: #424245;
  --rule-hover: #6e6e73; /* a card's edge under the pointer */
  --hairline: rgba(255, 255, 255, 0.16);
  --hairline-2: rgba(255, 255, 255, 0.12);
  --dashed: rgba(255, 255, 255, 0.26);
  --control-line: #86868b;
  --float-line: rgba(255, 255, 255, 0.16); /* the floating symbol switch */
  --cool-line: #424245; /* specialists: review rows */
  --cool-control: #86868b; /* specialists: the search field */
  --cool-frame: #424245; /* specialists: the map's frame */

  /* Tints */
  --wash: rgba(255, 255, 255, 0.08);
  --wash-strong: rgba(255, 255, 255, 0.14);
  --track: rgba(255, 255, 255, 0.16);
  --rail: rgba(255, 255, 255, 0.22); /* the scroll sequence's progress */

  /* Ink */
  --ink: #f5f5f7;
  --ink-2: #a1a1a6;
  --ink-strong: #ffffff;
  --ink-hover: #d2d2d7;
  --cap-ink: #1d1d1f; /* a symbol card's word: on the card's own tint */

  /* Accent */
  --blue: #2997ff;
  --blue-hover: #4aa7ff;
  --blue-surface: #2997ff;
  --blue-wash: rgba(41, 151, 255, 0.14);
  --on-blue: #00224d;

  /* States */
  --error: #ff6961;
  --danger: #ff6961;
  --ok-bg: #203a28;
  --ok-ink: #30d158;
  --bad-bg: #41292a;
  --bad-ink: #ff8a84;
  --info-bg: #1f3347;
  --info-ink: #6cb6ff;
  --badge-bg: #2c2c2e;
  --badge-ink: #d1d1d6;
  --badge-super-bg: #1f3347;
  --badge-super-ink: #6cb6ff;

  /* The global bar. The tray is #1d1d1f at 0.82 under the same blur: still
     glass, but dense enough that the links (#f5f5f7 at 0.68) keep 5.0:1 even
     when a white picture scrolls under the pill -- at 0.72 that fell to 3.8.
     The light tray holds 4.9:1 over black for the same reason. */
  --nav-tray: rgba(29, 29, 31, 0.82);
  --nav-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.08),
    0 8px 24px rgba(0, 0, 0, 0.5);
  --nav-cap: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.17),
    rgba(255, 255, 255, 0.11)
  );
  --nav-cap-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    inset 0 0 0 1px rgba(255, 255, 255, 0.1),
    0 1px 1px rgba(0, 0, 0, 0.3),
    0 4px 10px rgba(0, 0, 0, 0.35);
  --nav-cap-hover: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.22),
    rgba(255, 255, 255, 0.15)
  );
  --nav-cap-shadow-hover:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 0 0 1px rgba(255, 255, 255, 0.14),
    0 1px 2px rgba(0, 0, 0, 0.35),
    0 6px 14px rgba(0, 0, 0, 0.4);
  --nav-menu: #1d1d1f;
  --nav-menu-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.08),
    0 1px 2px rgba(0, 0, 0, 0.5),
    0 12px 32px rgba(0, 0, 0, 0.6);
  --nav-row: rgba(255, 255, 255, 0.1);
  --nav-cur: rgba(255, 255, 255, 0.08);
  --nav-cur-ring: rgba(255, 255, 255, 0.16);

  /* Shadows */
  --shadow-lift: 0 18px 36px -22px rgba(0, 0, 0, 0.9);
  --shadow-hi: 0 20px 44px -26px rgba(41, 151, 255, 0.5);
  --shadow-seg: 0 1px 3px rgba(0, 0, 0, 0.5);
  --shadow-float: 0 6px 20px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.5);
  --shadow-float-hover: 0 10px 26px rgba(0, 0, 0, 0.7), 0 1px 3px rgba(0, 0, 0, 0.5);

  /* The app's own grid-palette hues, used only inside the board demo so it
     matches the real product rather than the website. The same in both
     themes: the demo is a picture of the app. */
  --g-green-bg: #e7f6ec;
  --g-green-br: #2e7d4f;
  --g-green-tx: #14532d;
  --g-pink-bg: #fdeaf0;
  --g-pink-br: #b3325c;
  --g-pink-tx: #6b1332;
  --g-yellow-bg: #fdf3d8;
  --g-yellow-br: #9a7016;
  --g-yellow-tx: #4d3606;
  --g-blue-bg: #e6efff;
  --g-blue-br: #2f5bea;
  --g-blue-tx: #14225c;

  /* Shape */
  --r-pill: 980px;
  --r-lg: 28px;
  --r-md: 18px;
  --r-sm: 12px;

  /* Rhythm */
  --page: 1024px;
  --page-wide: 1240px;
  --gut: 22px;

  --ease: cubic-bezier(0.28, 0.11, 0.32, 1);
  --dur: 620ms;
}

/* The light theme: the site as it was before the switch, value for value.
   Repeated under @media print below (keep the two in step). */
:root:where([data-theme='light']) {
  color-scheme: light;

  /* One ground for the whole site, white (owner, 2026-10-19: "the
     background must be coherent everywhere"). Every page and every band sits
     on --paper; --paper-2 is only for surfaces on it (cards, tiles, panels). */
  --paper: #ffffff; /* page background (was #fbfbfd) */
  --paper-2: #f5f5f7; /* cards, tiles, panels */
  --card: #ffffff;
  --raised: #f5f5f7;
  --field: #ffffff;
  --seg-on: #ffffff;
  --card-quiet: #f5f5f7;

  --rule: #d2d2d7; /* hairlines where a band or the footer meets the page */
  --rule-hover: #d2d2d7;
  --hairline: rgba(0, 0, 0, 0.11);
  --hairline-2: rgba(0, 0, 0, 0.08);
  --dashed: rgba(0, 0, 0, 0.24);
  --control-line: #c7c7cc;
  --float-line: rgba(0, 0, 0, 0.1);
  --cool-line: #e6eaf2;
  --cool-control: #d8dee9;
  --cool-frame: #d8dee9;

  --wash: rgba(0, 0, 0, 0.045);
  --wash-strong: rgba(0, 0, 0, 0.08);
  --track: rgba(0, 0, 0, 0.1);
  --rail: rgba(0, 0, 0, 0.16);

  /* Ink on light */
  --ink: #1d1d1f;
  --ink-2: #6e6e73; /* 4.7:1 on --paper */
  --ink-strong: #000000;
  --ink-hover: #3a3a3c;
  --cap-ink: #1d1d1f;

  /* Accent */
  --blue: #0071e3; /* 4.6:1 on --paper */
  --blue-hover: #0077ed;
  --blue-surface: #0066cc; /* links on a --paper-2 card: 5.1:1 (--blue is 4.3:1 there) */
  --blue-wash: rgba(0, 113, 227, 0.08);
  --on-blue: #ffffff;

  --error: #b3261e;
  --danger: #d93025;
  --ok-bg: #e7f6ec;
  --ok-ink: #14532d;
  --bad-bg: #fdeaf0;
  --bad-ink: #6b1332;
  --info-bg: #e6efff;
  --info-ink: #14225c;
  --badge-bg: #eef1f6;
  --badge-ink: #46506a;
  --badge-super-bg: #e5edff;
  --badge-super-ink: #1b3faa;

  /* Greyer than the page so the pill reads as a surface rather than as
     floating text (see .globalnav-inner). */
  --nav-tray: rgba(236, 235, 232, 0.92);
  --nav-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 8px 24px rgba(0, 0, 0, 0.06);
  --nav-cap: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.98),
    rgba(255, 255, 255, 0.82)
  );
  --nav-cap-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 0 0 1px rgba(0, 0, 0, 0.11),
    0 1px 1px rgba(0, 0, 0, 0.05),
    0 4px 10px rgba(0, 0, 0, 0.07);
  --nav-cap-hover: linear-gradient(
    180deg,
    rgba(255, 255, 255, 1),
    rgba(255, 255, 255, 0.92)
  );
  --nav-cap-shadow-hover:
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 0 0 1px rgba(0, 0, 0, 0.14),
    0 1px 2px rgba(0, 0, 0, 0.06),
    0 6px 14px rgba(0, 0, 0, 0.09);
  --nav-menu: #ffffff;
  --nav-menu-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 8px 24px rgba(0, 0, 0, 0.10);
  --nav-row: rgba(0, 0, 0, 0.07);
  --nav-cur: rgba(0, 0, 0, 0.05);
  --nav-cur-ring: rgba(0, 0, 0, 0.11);

  --shadow-lift: 0 18px 36px -22px rgba(0, 0, 0, 0.45);
  --shadow-hi: 0 20px 44px -26px rgba(45, 108, 223, 0.55);
  --shadow-seg: 0 1px 3px rgba(0, 0, 0, 0.12);
  --shadow-float: 0 6px 20px rgba(0, 0, 0, 0.14), 0 1px 3px rgba(0, 0, 0, 0.08);
  --shadow-float-hover: 0 10px 26px rgba(0, 0, 0, 0.18), 0 1px 3px rgba(0, 0, 0, 0.08);
}

/* --------------------------------------------------------------- reset */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  /* SF on Apple platforms, a close grotesque everywhere else. Atkinson
     Hyperlegible is listed because the app offers it and no layout here may
     break when a reader substitutes it. */
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text',
    'Helvetica Neue', 'Atkinson Hyperlegible', Helvetica, Arial, sans-serif;
  font-size: 17px;
  line-height: 1.47059;
  letter-spacing: -0.022em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

/* ----------------------------------------------------------------- type */

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.display {
  font-size: clamp(40px, 7.4vw, 88px);
  line-height: 1.05;
  letter-spacing: -0.018em;
}

.headline {
  font-size: clamp(32px, 5.2vw, 64px);
  line-height: 1.0625;
  letter-spacing: -0.012em;
}

.subhead {
  font-size: clamp(24px, 3vw, 40px);
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.eyebrow {
  font-size: clamp(19px, 1.6vw, 21px);
  font-weight: 600;
  letter-spacing: 0.004em;
  color: var(--blue);
  margin: 0 0 10px;
}

.intro {
  font-size: clamp(19px, 1.9vw, 28px);
  line-height: 1.3;
  letter-spacing: 0.004em;
  font-weight: 400;
  color: var(--ink-2);
  margin: 22px auto 0;
  max-width: 46ch;
}

.body-copy {
  font-size: 17px;
  line-height: 1.5;
  color: var(--ink-2);
  margin: 16px 0 0;
  max-width: 60ch;
}

p {
  margin: 0 0 16px;
}

p:last-child {
  margin-bottom: 0;
}

/* Dark bands invert the whole ink ramp. */
.band-dark {
  background: var(--black);
  color: var(--ink-d);
}

.band-dark .eyebrow {
  color: var(--blue-dark);
}

.band-dark .intro,
.band-dark .body-copy,
.band-dark .footnote {
  color: var(--ink-d2);
}

.band-dark a {
  color: var(--blue-dark);
}

/* The light bands. They used to alternate near-white and light grey; with
   one white ground they are the same band, and the classes stay so the pages
   keep their structure. .band-white is the product pages' name for it.
   .band-dark (above) is kept for any page that still asks for black, but no
   page on the site uses it now. */
.band-light,
.band-grey,
.band-white {
  background: var(--paper);
  color: var(--ink);
}

/* --------------------------------------------------------------- links */

a {
  color: var(--blue);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* Links inside running prose are always underlined: a blue word alone is
   colour carrying meaning. */
.body-copy a,
.footnote a,
.prose a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 4px;
  border-radius: 6px;
}

.band-dark :focus-visible {
  outline-color: var(--blue-dark);
}

.skip {
  position: absolute;
  left: 20px;
  top: -120px;
  z-index: 9999;
  background: var(--card);
  color: var(--ink);
  border: 2px solid var(--blue);
  border-radius: var(--r-sm);
  padding: 14px 20px;
  font-size: 17px;
  font-weight: 600;
  transition: top 180ms var(--ease);
}

.skip:focus {
  top: 20px;
  text-decoration: none;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* -------------------------------------------------------------- layout */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gut);
}

.wrap-wide {
  max-width: var(--page-wide);
}

.center {
  text-align: center;
}

.center .intro,
.center .body-copy {
  margin-inline: auto;
}

section {
  padding-block: clamp(70px, 9vw, 130px);
}

.tight {
  padding-block: clamp(48px, 6vw, 88px);
}

/* Two tight bands in a row used to be told apart by their colours; on one
   white ground their paddings simply stacked into a hole. The second one
   starts where the first one's padding ends. */
.tight + .tight {
  padding-top: 0;
}

/* --------------------------------------------------------------- nav ---
   A floating pill, centred at the top of the page rather than a full-width
   bar pinned to its edge. The links keep a 44px hit area through padding
   even though the label is small, which is the one place this site knowingly
   departs from its visual reference.

   The bar itself is transparent and only provides the sticky positioning and
   the space above; the PILL is .globalnav-inner, sized to its contents so it
   stays centred whatever the page width.
   -------------------------------------------------------------------- */

.globalnav {
  position: sticky;
  top: 0;
  z-index: 9000;
  padding: 18px var(--gut) 0;
  /* No background and no border: the page shows through around the pill.
     pointer-events is handed back to the pill itself so the transparent
     gutter either side does not swallow clicks on whatever is beneath it. */
  pointer-events: none;
}

.globalnav-inner {
  pointer-events: auto;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 6px 10px 6px 6px;
  border-radius: var(--r-pill);
  /* Greyer than the page so the pill reads as a surface rather than as
     floating text. Lightened 15% toward white from the first pass; the
     capsule on the current page now carries most of the shape, so the tray
     underneath it does not have to work as hard. */
  background: var(--nav-tray);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  box-shadow: var(--nav-shadow);
}

.globalnav-brand {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  /* The badge is 34px, but accessibility.html promises every control is at
     least 44 by 44 "including the small type in the global bar". The extra
     5px either side is hit area only; the circle does not move. */
  min-width: 44px;
  margin-inline-end: 6px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}

/* The word "Super" is hidden beside the badge on the pill, which is tight on
   room -- but only visually. It stays in the accessibility tree, so the link
   is still "Super" to a screen reader rather than an unnamed graphic. */
.globalnav-brand .brand-word {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.globalnav-brand:hover {
  text-decoration: none;
  color: var(--ink);
}

/* The mPower mark: a dot at the centre of a circle. It draws its own ring, so
   unlike the badge it replaced it must NOT sit on a filled disc -- that would
   read as a circle inside a circle. It inherits currentColor, which is how the
   original is built too: the same geometry is recoloured per section rather
   than being locked to one brand colour. */
.globalnav-brand .mark {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  flex: none;
  color: var(--ink);
}

/* 30px inside a 34px box, the size the mark ships at. The 32-unit viewBox and
   its circle values are left exactly as drawn -- rescaling the numbers by hand
   thins the ring and shrinks the dot, and the mark stops looking like itself. */
.globalnav-brand .mark svg {
  width: 30px;
  height: 30px;
}

.globalnav-list {
  display: flex;
  align-items: center;
  gap: 2px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.globalnav-list a {
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding-inline: 14px;
  font-size: 14px;
  letter-spacing: -0.01em;
  color: var(--ink);
  opacity: 0.68;
  border-radius: var(--r-pill);
}

.globalnav-list a:hover,
.globalnav-list a:focus-visible {
  opacity: 1;
  text-decoration: none;
  background: var(--wash);
}

/* Current page: full tone, heavier weight, and a glass capsule lifted off the
   tray.

   WHAT ACTUALLY CARRIES THE MARK. The capsule is the visible design, but it
   is a white shape on a near-white tray: measured, its fill is about 1.15:1
   against the tray, so it is a soft cue by nature -- that is what makes it
   read as glass rather than as a button. The load-bearing signals are the
   TEXT: weight 600 against 400, and full tone (about 14:1 on the capsule)
   against the 0.68 opacity of its siblings (about 5.4:1). Both are
   typographic, so both survive greyscale, a dimmed screen and a cheap panel.
   accessibility.html is worded to match that order, and must stay that way.

   The rim is a DARK hairline, not a white one. An earlier pass used
   rgba(255,255,255,0.5) here and a pixel scan across the capsule's left edge
   read 237 (tray) -> 235 -> 245 -> 254: the white rim lightened the boundary
   instead of drawing it, and the drop shadows are y-offset so they darken
   only underneath. The capsule had no side edge at all.

   Deliberately NOT a backdrop-filter. This element is a child of the blurred
   .globalnav-inner, and a nested backdrop-filter samples a reset backdrop
   root -- the same trap that made the mobile menu see-through.

   In the dark theme the same capsule is a lighter glass on the dark tray
   (--nav-cap): white at 11-17%, with a light rim and a deeper shadow, and the
   text carries the mark the same way, weight and full tone. */
.globalnav-list a[aria-current='page'] {
  opacity: 1;
  font-weight: 600;
  background: var(--nav-cap);
  box-shadow: var(--nav-cap-shadow);
}

/* Without this the current page is the one item in the bar that answers the
   pointer with nothing: the rule above and .globalnav-list a:hover have equal
   specificity, so this one wins outright and swallows the hover tint. The
   capsule brightens and lifts rather than darkening, so the selected state
   still reads as selected while the pointer is on it. */
.globalnav-list a[aria-current='page']:hover {
  background: var(--nav-cap-hover);
  box-shadow: var(--nav-cap-shadow-hover);
}

/* Windows high contrast repaints backgrounds and drops every box-shadow, so
   the capsule above simply does not exist there and weight would be carrying
   the mark on its own. The underline comes back for that mode only -- it is
   the one place the glass cannot render at all. */
@media (forced-colors: active) {
  .globalnav-list a[aria-current='page'] {
    text-decoration: underline;
    text-underline-offset: 6px;
  }
}

.nav-toggle {
  display: none;
  margin-left: auto;
  width: 44px;
  height: 44px;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  place-items: center;
}

.nav-toggle svg {
  width: 18px;
  height: 18px;
}

/* The dark/light switch (assets/js/theme.js does the switching; this only
   draws it). It sits in the pill after the list, and once the list folds
   away it sits beside the menu button. Drawn as one more item of the bar:
   the same ink at the same 0.68 as the links, full tone and the same wash
   under the pointer, and the 44px round target the bar holds itself to.
   Its label says the state ("Dark mode") and aria-pressed carries it. */
.theme-toggle {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink);
  opacity: 0.68;
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.theme-toggle svg {
  display: block;
  width: 20px;
  height: 20px;
}

.theme-toggle:hover,
.theme-toggle:focus-visible {
  opacity: 1;
  background: var(--wash);
}

.theme-toggle:active {
  opacity: 1;
  background: var(--wash-strong);
}

/* The site's ring, kept round: the global :focus-visible squares the corners
   to 6px, which on a circle reads as a different, boxed control. */
.theme-toggle:focus-visible {
  border-radius: 50%;
  outline-offset: 2px;
}

/* --------------------------------------------------------------- CTAs */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 30px;
  align-items: center;
  margin-top: 28px;
}

.center .cta-row {
  justify-content: center;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 23px;
  border-radius: var(--r-pill);
  background: var(--blue);
  color: var(--on-blue);
  font-size: 17px;
  line-height: 1.2;
  font-weight: 400;
  letter-spacing: -0.022em;
  border: 1px solid var(--blue);
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease);
}

/* A button the script hides must stay hidden: the display above outranks the
   browser's own [hidden] rule, which is how "Sort by distance" used to show
   on a single specialist's page where it does nothing. */
.btn[hidden] { display: none; }

/* A button that cannot be pressed yet looks it; the sentence beside it says
   why (colour and opacity are never the only sign). */
.btn:disabled,
.btn:disabled:hover {
  opacity: 0.45;
  cursor: not-allowed;
  background: var(--blue);
  border-color: var(--blue);
}

.btn-secondary:disabled,
.btn-secondary:disabled:hover { background: transparent; }

.btn:hover {
  background: var(--blue-hover);
  border-color: var(--blue-hover);
  color: var(--on-blue);
  text-decoration: none;
}

.btn-secondary {
  background: transparent;
  color: var(--blue);
}

.btn-secondary:hover {
  background: var(--blue-wash);
  color: var(--blue);
}

.band-dark .btn {
  background: var(--blue-dark);
  border-color: var(--blue-dark);
  color: #00224d;
}

.band-dark .btn:hover {
  background: #4aa7ff;
  border-color: #4aa7ff;
  color: #00224d;
}

.band-dark .btn-secondary {
  background: transparent;
  color: var(--blue-dark);
}

/* The chevron link. The arrow is a glyph in a span so it can slide on hover
   without moving the label. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 17px;
  letter-spacing: -0.022em;
  color: var(--blue);
}

.link-arrow:hover {
  text-decoration: underline;
}

.link-arrow .chev {
  display: inline-block;
  margin-left: 4px;
  transition: transform 180ms var(--ease);
}

.link-arrow:hover .chev {
  transform: translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
  .link-arrow:hover .chev {
    transform: none;
  }
}

/* ---------------------------------------------------------------- hero */

.hero {
  padding-block: clamp(56px, 7vw, 96px) clamp(40px, 5vw, 72px);
  overflow: hidden;
}

.hero .display {
  margin-bottom: 0;
}

/* The product's own app icon at the top of its own page, above the eyebrow.

   The icons are white tiles and the hero band is near-white, so the tile is
   given the shape and the soft shadow an app icon has on a home screen;
   without them it is a white square that barely separates from the page.
   aspect-ratio keeps the space reserved before the PNG has loaded, which is
   what stops the headline jumping down the page a moment after it is read. */
.hero-logo {
  display: block;
  width: clamp(88px, 10vw, 132px);
  height: auto;
  aspect-ratio: 1;
  margin: 0 auto clamp(16px, 2.4vw, 28px);
  border-radius: 22.37%;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 8px 24px rgba(0, 0, 0, .08);
}

.hero-media {
  margin-top: clamp(40px, 5vw, 72px);
}

/* The big centred product shot, with the soft ground shadow Apple uses to
   float hardware over a flat band. */
.stage {
  max-width: 940px;
  margin-inline: auto;
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: 0 26px 60px -22px rgba(0, 0, 0, 0.35);
}

.band-dark .stage {
  box-shadow: 0 26px 70px -20px rgba(0, 0, 0, 0.9);
}

.stage img {
  width: 100%;
}

/* ------------------------------------------------------- scroll reveal */

.reveal-on .reveal {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.reveal-on .reveal.is-in {
  opacity: 1;
  transform: none;
}

/* The hero shot settles on load, in CSS, deliberately NOT through the scroll
   observer. It is the most important image on the page and it is above the
   fold, so nothing about whether it is visible should depend on a script
   running — an earlier draft tied it to the observer and a stale cached
   script left it at opacity 0 with the page looking empty. */
.hero-media .stage,
.hero-media .ipad-wrap,
.hero-media .stage-placeholder {
  animation: hero-settle 820ms var(--ease) both;
}

@keyframes hero-settle {
  from {
    opacity: 0;
    transform: scale(0.965);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-media .stage,
  .hero-media .ipad-wrap,
  .hero-media .stage-placeholder {
    animation: none;
  }
}


/* --------------------------------------------------------------- modules
   The course contents as a numbered list, in columns so twenty titles read as
   a syllabus rather than a scroll. The number is drawn rather than left to the
   marker, because a list-item marker cannot be given its own colour without
   ::marker, which Safari only styles for a subset of properties.
   -------------------------------------------------------------------- */

.modules {
  list-style: none;
  counter-reset: mod;
  margin: 32px 0 0;
  padding: 0;
  columns: 2;
  column-gap: 44px;
}

.modules li {
  counter-increment: mod;
  break-inside: avoid;
  display: grid;
  grid-template-columns: 2.2em 1fr;
  gap: 10px;
  padding: 9px 0;
  font-size: 15.5px;
  line-height: 1.45;
}

.modules li::before {
  content: counter(mod, decimal-leading-zero);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  /* The number is a label, not decoration, so it stays above the body-text
     floor rather than fading to a hint: 5.1:1 on white, 8.2:1 on black. */
  color: var(--ink-2);
}

.band-dark .modules li::before { color: var(--ink-d2); }

@media (max-width: 833px) {
  .modules { columns: 1; }
}

.note-line {
  margin: 26px 0 0;
  max-width: 62ch;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

.band-dark .note-line { color: var(--ink-d2); }

/* --------------------------------------------------------------- scatter
   Small photographs scattered behind the hero text: rounded, tilted, and
   lifted off the page.

   They sit on the SECTION, not inside .wrap, because .wrap is the text column
   and anything inside it can only ever be above or below the words. Absolute
   placement on the section is what lets them sit beside the text -- and the
   percentages below are chosen so they clear the column rather than pass under
   it. A photograph under a headline is a contrast problem no colour choice
   fixes, and this site publishes a 4.5:1 floor.

   .hero already has overflow:hidden, so a card that hangs off the edge is
   cropped instead of adding a scrollbar.
   -------------------------------------------------------------------- */

.hero {
  position: relative;
}

/* The text column sits above them, and keeps its own stacking context so a
   card can never land on top of a link. */
.hero > .wrap {
  position: relative;
  z-index: 1;
}

.scatter {
  position: absolute;
  inset: 0;
  z-index: 0;
  /* Decoration must never eat a click meant for the page behind it. */
  pointer-events: none;
}

.scatter-card {
  position: absolute;
  margin: 0;
  width: clamp(210px, 24.375vw, 367.5px);
  border-radius: 20px;
  overflow: hidden;
  /* Rounding a figure does nothing unless the image inside is clipped by it,
     which is what overflow does here -- and Safari needs the isolation to
     apply the clip to a transformed child at all. */
  isolation: isolate;
  background: var(--paper-2);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.07),
    0 18px 40px -16px rgba(0, 0, 0, 0.38);
}

/* A slow drift, so the wall of text has something breathing beside it.

   It animates `translate`, NOT `transform`. The tilt below lives in
   `transform`, and a transform in a keyframe replaces it outright -- the cards
   would snap square the moment the animation took hold. `translate` is its own
   property and composes with the tilt instead of overwriting it, and because
   the individual properties resolve before `transform`, each card is rotated
   in place and then moved straight up and down whatever angle it sits at.

   Vertical only, so it cannot carry a card into the text column: the clearance
   established above is horizontal and this never touches it.

   The three are given different periods and started part-way through, so they
   drift independently rather than bobbing in step like one object. The periods
   are deliberately not multiples of each other, or they would keep meeting. */
@keyframes scatter-drift {
  0%, 100% { translate: 0 calc(var(--rise) * 0.5); }
  50%      { translate: 0 calc(var(--rise) * -0.5); }
}

.scatter-card {
  --rise: 16px;
  animation: scatter-drift var(--drift, 11s) ease-in-out infinite;
}

.sc-1 { --rise: 15px; --drift: 9s;  animation-delay: -2.4s; }
.sc-2 { --rise: 19px; --drift: 13s; animation-delay: -7.1s; }
.sc-3 { --rise: 13px; --drift: 11s; animation-delay: -4.6s; }

/* Removed, not slowed. The site's accessibility page says animation is taken
   away under this setting rather than shortened, and the cards simply rest
   where they are. */
@media (prefers-reduced-motion: reduce) {
  .scatter-card { animation: none; }
}

.scatter-card img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* Anchored to the EDGE OF THE TEXT COLUMN, not to the edge of the window.

   Placing them at a percentage of the viewport only clears the column while a
   card is smaller than the free margin beside it, and it stops being true the
   moment either the card grows or the window narrows -- silently, and in the
   one direction that matters, because what a card then covers is the headline.
   Anchoring at 50% + half the column takes the card's inner edge off the
   column itself, so the clearance holds at every width and at any card size.

   Outboard of that they are free to run off the side of the window; .hero
   crops them rather than growing a scrollbar. That is what lets them be this
   large on a laptop at all -- at 1440px there is only about 200px of margin
   beside the column, and a card is wider than that. Cropped and large reads as
   a photograph continuing past the edge; shrunk to fit reads as a thumbnail.

   --page is 1024px, so half of it is 512px; the extra is the gap to the text
   plus room for the tilt, which throws a corner out beyond the box. */
.sc-1 { right: calc(50% + 512px + 14px); top: 14%;    transform: rotate(-7deg); }
.sc-2 { left:  calc(50% + 512px + 14px); top: 30%;    transform: rotate(6deg); }
.sc-3 { right: calc(50% + 512px + 46px); bottom: 10%; transform: rotate(4deg); }

/* Below this too little of a card is left on screen to read as a photograph
   rather than as a stray edge, so they go entirely. They are decoration; the
   words are not. */
@media (max-width: 1300px) {
  .scatter { display: none; }
}

/* -------------------------------------------------------------- symwall
   Vertical symbol cards: a portrait card per symbol, wearing its Fitzgerald
   tint, tilted and lifted so the row reads as cards dropped on a table.
   The custom properties are set per card in the markup -- the tint IS data
   (the pack assigns it), so it belongs with the symbol, not in a stylesheet
   that cannot know which card is which.
   -------------------------------------------------------------------- */

.symwall {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: clamp(10px, 1.6vw, 22px);
  margin-top: clamp(36px, 4vw, 56px);
  margin-bottom: clamp(28px, 3vw, 40px);
}

.symcard {
  margin: 0;
  width: clamp(96px, 11vw, 150px);
  aspect-ratio: 3 / 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 10px 8px 12px;
  /* The tint is the symbol's own colour (the pack assigns it), so the card
     keeps it in both themes, and its word stays dark ink on it. The fallback
     is the light grey the cards have always had, as a literal: a dark card
     would put a white picture ground on black. */
  background: var(--tint, #f5f5f7);
  border-radius: 18px;
  transform: rotate(var(--tilt, 0deg)) translateY(var(--lift, 0));
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.08),
    0 16px 34px -14px rgba(0, 0, 0, 0.35);
  transition: transform 300ms var(--ease), box-shadow 300ms var(--ease);
}

.symcard img {
  width: 78%;
  height: auto;
  aspect-ratio: 1;
  object-fit: contain;
}

.symcard figcaption {
  font-size: clamp(12px, 1.2vw, 15px);
  font-weight: 600;
  letter-spacing: -0.01em;
  /* Read by assets/js/paac-board.js for the canvas copies of these cards. */
  color: var(--cap-ink);
  text-align: center;
  line-height: 1.15;
}

.symcard:hover {
  transform: rotate(0deg) translateY(calc(var(--lift, 0px) - 6px)) scale(1.04);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.08),
    0 24px 48px -16px rgba(0, 0, 0, 0.42);
}

@media (prefers-reduced-motion: reduce) {
  .symcard { transition: none; }
  .symcard:hover {
    transform: rotate(var(--tilt, 0deg)) translateY(var(--lift, 0));
  }
}

/* ------------------------------------------------------------- symboard
   The symbol wall, opened out into the whole set: the ten cards above take
   their places at the middle of a board 43 across and 16 down while the
   other 678 arrive around them. assets/js/paac-board.js drives it.

   Nothing here applies until that script has the sheet and adds .is-live, so
   a page with no JavaScript -- or one whose sheet did not load -- keeps the
   ten cards it always had, in flow, unchanged. */
.symboard { position: relative; }

.symboard-field { display: none; }

.symboard.is-live .symboard-pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: clip;
}

/* The wrap would otherwise shrink to its content inside a flex row, which
   changes where the ten cards wrap and so where they are measured. */
.symboard.is-live .symboard-pin > .wrap { width: 100%; }

.symboard.is-live .symboard-field {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.symboard.is-live .symwall {
  position: relative;
  z-index: 1;
  margin-top: 0;
  margin-bottom: 0;
}

/* The hand-over. The canvas is already drawing these ten cards, at the
   positions the real ones were measured at, before this hides them -- so the
   frame it happens on is identical to the one before it and nothing moves
   until the page is scrolled. */
.symboard.is-handed .symwall {
  opacity: 0;
  pointer-events: none;
}


/* --------------------------------------------------------------- tiles */

.tiles {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.tile {
  background: var(--paper-2);
  border-radius: var(--r-lg);
  padding: clamp(32px, 4vw, 52px);
  min-height: 340px;
  display: flex;
  flex-direction: column;
  color: var(--ink);
  text-align: center;
  align-items: center;
  justify-content: flex-start;
}

.band-dark .tile {
  background: #101010;
  color: var(--ink-d);
}

.tile h3 {
  font-size: clamp(24px, 2.4vw, 32px);
  margin-bottom: 10px;
}

.tile p {
  font-size: 17px;
  color: var(--ink-2);
  max-width: 34ch;
}

.band-dark .tile p {
  color: var(--ink-d2);
}

.tile .tile-art {
  margin-top: auto;
  padding-top: 28px;
  width: 100%;
}

.tile .tile-art img {
  border-radius: 14px;
  width: 100%;
  /* A screenshot whose own ground matches the tile's -- a dark tool panel on
     the dark tile, a white page on the light one -- loses its edge and reads
     as cut off. The hairline keeps the picture's outline in both themes. */
  box-shadow: 0 0 0 1px var(--hairline);
}

a.tile:hover {
  text-decoration: none;
}

/* A tile is a --paper-2 card on the white ground, where --blue falls to
   4.3:1; its links take the darker blue (in the dark theme --blue-surface is
   the bright blue again: 5.6:1 on #1d1d1f). */
.tile .link-arrow,
.tile a:not(.btn) {
  color: var(--blue-surface);
}

.band-dark .tile .link-arrow,
.band-dark .tile a:not(.btn) {
  color: var(--blue-dark);
}

/* -------------------------------------------------------- feature rows */

.feature {
  display: grid;
  gap: clamp(32px, 4vw, 64px);
  align-items: center;
}

@media (min-width: 860px) {
  .feature {
    grid-template-columns: 1fr 1.2fr;
  }
  .feature.flip .feature-copy {
    order: 2;
  }
}

.feature + .feature {
  margin-top: clamp(64px, 8vw, 120px);
}

.feature-copy h3 {
  font-size: clamp(26px, 2.8vw, 40px);
  line-height: 1.1;
}

.feature-copy .eyebrow {
  font-size: 17px;
}

figure {
  margin: 0;
}

figcaption {
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink-2);
  margin-top: 14px;
}

.band-dark figcaption {
  color: var(--ink-d2);
}

/* -------------------------------------------------------------- specs */

.specs {
  display: grid;
  gap: 0;
  max-width: 780px;
  margin-inline: auto;
}

.spec-row {
  display: grid;
  gap: 8px 40px;
  padding: 24px 0;
  border-top: 1px solid var(--hairline);
}

.band-dark .spec-row {
  border-top-color: rgba(255, 255, 255, 0.16);
}

@media (min-width: 700px) {
  .spec-row {
    grid-template-columns: 200px 1fr;
  }
}

.spec-row dt {
  font-weight: 600;
  font-size: 17px;
}

.spec-row dd {
  margin: 0;
  color: var(--ink-2);
  font-size: 17px;
}

.band-dark .spec-row dd {
  color: var(--ink-d2);
}

/* ------------------------------------------------------------- pricing */

.plans {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  align-items: stretch;
}

.plan {
  background: var(--card);
  border-radius: var(--r-lg);
  padding: clamp(28px, 3vw, 40px);
  display: flex;
  flex-direction: column;
  text-align: left;
  border: 1px solid var(--rule);
}

.band-dark .plan {
  background: #101010;
  border-color: rgba(255, 255, 255, 0.14);
}

/* The recommended plan is marked by border weight and by the words "Most
   popular", so the recommendation survives greyscale. */
.plan.featured {
  border: 2px solid var(--blue);
  padding: calc(clamp(28px, 3vw, 40px) - 1px);
}

.band-dark .plan.featured {
  border-color: var(--blue-dark);
}

.plan-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.plan h3 {
  font-size: 24px;
}

.badge {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  padding: 5px 10px;
  border-radius: var(--r-pill);
  background: var(--blue);
  color: var(--on-blue);
}

.band-dark .badge {
  background: var(--blue-dark);
  color: #00224d;
}

.plan .price {
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 18px 0 4px;
}

.plan .terms {
  font-size: 14px;
  color: var(--ink-2);
  margin-bottom: 22px;
}

.band-dark .plan .terms {
  color: var(--ink-d2);
}

.plan ul {
  list-style: none;
  padding: 0;
  margin: 0 0 28px;
  flex: 1;
}

.plan li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 10px;
  font-size: 15px;
  line-height: 1.45;
}

.plan li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.42em;
  width: 14px;
  height: 7px;
  border-left: 2px solid var(--blue);
  border-bottom: 2px solid var(--blue);
  transform: rotate(-45deg);
}

.band-dark .plan li::before {
  border-color: var(--blue-dark);
}

/* ------------------------------------------------------------ footnote */

.footnote {
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink-2);
  max-width: 76ch;
  margin-inline: auto;
}

.footnote ol {
  padding-left: 1.2em;
  margin: 0;
}

.footnote li {
  margin-bottom: 6px;
}

/* -------------------------------------------------------------- pending */

.pending {
  max-width: 660px;
  margin-inline: auto;
  border: 1px dashed var(--dashed);
  border-radius: var(--r-lg);
  padding: clamp(36px, 5vw, 64px);
  text-align: center;
  background: var(--card);
}

.band-dark .pending {
  background: #101010;
  border-color: rgba(255, 255, 255, 0.26);
}

.slot {
  border: 1px dashed var(--dashed);
  border-radius: var(--r-md);
  background: var(--paper-2);
  min-height: 220px;
  display: grid;
  place-items: center;
  color: var(--ink-2);
  font-size: 14px;
  text-align: center;
  padding: 20px;
}

.band-dark .slot {
  background: #101010;
  border-color: rgba(255, 255, 255, 0.26);
  color: var(--ink-d2);
}

/* --------------------------------------------------------------- footer */

.globalfooter {
  background: var(--paper);
  border-top: 1px solid var(--rule);
  padding-block: 40px 24px;
  font-size: 12px;
  color: var(--ink-2);
}

.globalfooter .wrap {
  max-width: var(--page-wide);
}

.footer-note {
  padding-bottom: 18px;
  border-bottom: 1px solid var(--hairline);
}

.footer-grid {
  display: grid;
  gap: 28px;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  padding-block: 26px;
  border-bottom: 1px solid var(--rule);
}

.footer-grid h4 {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 8px;
}

.footer-grid ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* 44 in both directions, even for a short word like "Tour". The reference
   design sets these much smaller; the accessibility page on this site
   promises 44, and the promise wins. */
.footer-grid a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  color: var(--ink-2);
  font-size: 12px;
}

.footer-grid a:hover {
  color: var(--ink);
  text-decoration: underline;
}

.footer-legal {
  padding-top: 18px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  align-items: center;
}

/* News joined the bar on 26 October 2026: eleven links. At the links' 14px
   padding the widest language then needs a 1183px window (Polish, measured
   in the built site with the longest likely word for "News" in each
   language: "Aktualności", "Neuigkeiten", "Actualités"), so between 1100
   and 1240px the padding narrows with the window instead, from 8px at 1100
   to the full 14px at 1240, and a short label is held at 44px wide and
   centred, so no link is a smaller target than the site's 44px floor. Signed
   out, every language keeps one row there (measured with Apple's system font,
   and with Arial, Windows' fallback, plus its 17px scrollbar); from 1240px up
   and below 1100px nothing changes. Only the page links: the signed-in
   avatar is an <a> in the list too, and a 44px minimum width turned its
   circle into an oval. */
@media (min-width: 1100px) and (max-width: 1239px) {
  .globalnav-list > li:not(.globalnav-auth) > a {
    min-width: 44px;
    justify-content: center;
    padding-inline: clamp(8px, calc(8px + (100vw - 1100px) * 0.0429), 14px);
  }
}

/* Signed in, the slot holds the avatar and a "Sign out" pill in place of the
   "Sign in" pill: 50 to 80px wider, and in French, Portuguese, Spanish,
   Finnish, Polish and Croatian the bar above then wrapped to two rows (or
   broke "Sign out" in two) anywhere from 1100 to 1249px. So, signed in and
   only then, up to 1300px: no gap between the links (their own padding
   already parts them), the links' padding narrows from 6px at 1100 to the
   full 14px at 1300, and the slot is a little tighter (a 6px gap, a 12px
   pill). Measured on 26 October 2026 in all 17 languages, signed in and
   out, on the page with the longest current label: at least 30px to spare
   with the system font, and with Arial plus a 17px scrollbar. */
@media (min-width: 1100px) and (max-width: 1299px) {
  .globalnav-list:has(.auth-avatar) {
    gap: 0;
  }

  .globalnav-list:has(.auth-avatar) > li:not(.globalnav-auth) > a {
    min-width: 44px;
    justify-content: center;
    padding-inline: clamp(6px, calc(6px + (100vw - 1100px) * 0.04), 14px);
  }

  .globalnav-auth:has(.auth-avatar) {
    gap: 6px;
    margin-inline-start: 2px;
  }

  .globalnav-auth .auth-who {
    padding-inline: 12px;
  }
}

/* -------------------------------------------------------------- mobile */

/* The bar collapses to its menu button below 1100px, not with the rest of the
   phone layout at 833px: since SuperCoach joined it, ten items in one pill no
   longer fit at tablet widths -- in English it wrapped to two rows, and in
   Finnish, Polish and Spanish it pushed the page sideways. Every language fits
   on one row from 1040px (measured in the built site, 14 Oct 2026); 1100
   leaves room for wider system fonts. */
@media (max-width: 1099px) {
  .nav-toggle {
    display: grid;
  }

  /* The pill keeps the brand and the toggle; the list drops out of it as its
     own rounded panel, aligned to the pill rather than to the screen edges. */
  .globalnav-inner {
    width: 100%;
    justify-content: space-between;
    padding-inline: 8px;
  }

  .globalnav-list {
    position: absolute;
    inset: calc(100% + 8px) 0 auto;
    margin: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* Opaque, and deliberately WITHOUT a backdrop-filter of its own. This panel
       is a child of .globalnav-inner, which is blurred; a nested backdrop-filter
       samples a reset backdrop root, and the panel then composites as if it were
       translucent -- the hero heading reads straight through the menu links.
       Nothing here needs to be see-through; it needs to be readable.
       White in the light theme; in the dark one a #1d1d1f panel with a faint
       rim, since a black panel on a black page would have no edge at all. */
    background: var(--nav-menu);
    border-radius: var(--r-lg);
    box-shadow: var(--nav-menu-shadow);
    padding: 8px 16px 12px;
    display: none;
  }

  /* Eleven rows and Sign in are about 580px: taller than a phone held
     sideways. The bar is sticky and the menu hangs from it, so the page's
     own scrolling never reaches rows below the window; the menu scrolls
     inside itself instead (it is shorter than this everywhere else, where
     nothing changes). 96px is the bar and the gap above the menu. */
  .globalnav-list.open {
    display: flex;
    max-height: calc(100vh - 96px);
    max-height: calc(100dvh - 96px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* Full-width rows: as inline boxes the separators and the current-page
     capsule were only as long as each label, a ragged column of stubs that
     the dark menu made plain. */
  .globalnav-list a {
    display: flex;
    height: 50px;
    font-size: 17px;
    padding-inline: 4px;
    opacity: 1;
    border-bottom: 1px solid var(--nav-row);
    border-radius: 0;
  }

  .globalnav-list a:hover {
    background: none;
  }

  /* The dropdown is paper, so the bright capsule from the pill would be
     invisible on it. Same shape, drawn the other way round: a light fill
     lifted off white instead of a white one lifted off grey. The separator
     under it is only made transparent, never removed, so the row keeps its
     height and the list does not shift when the current page changes. */
  .globalnav-list a[aria-current='page'] {
    background: var(--nav-cur);
    /* Stronger than the row separators, so the marked row is outlined more
       strongly than the rows around it rather than less. */
    box-shadow: inset 0 0 0 1px var(--nav-cur-ring);
    border-radius: 10px;
    border-bottom-color: transparent;
  }

  /* Beside the menu button now, and at the menu button's full tone. */
  .theme-toggle {
    opacity: 1;
  }
}

@media (max-width: 833px) {
  .btn,
  .link-arrow {
    width: 100%;
  }

  .link-arrow {
    justify-content: center;
  }

  .cta-row {
    flex-direction: column;
    gap: 10px;
  }

  .feature-copy {
    text-align: center;
  }

  .feature-copy .body-copy {
    margin-inline: auto;
  }
}

@media print {
  .globalnav,
  .cta-row,
  .scrolly-progress,
  .theme-toggle {
    display: none;
  }
  body {
    background: #fff;
    color: #000;
  }
}

/* =========================================================================
   The scroll sequence
   =========================================================================

   One iPad, pinned in view, while the copy for each step scrolls past it. The
   device changes attitude at every step — turn, zoom, tilt, roll, revolve —
   and the screenshot inside cross-fades, so the whole tour reads as a single
   continuous move rather than as a stack of separate pictures.

   Three things this must survive, all of which matter more than the effect:

   1. NO JAVASCRIPT. `.scrolly` only becomes sticky once the script adds
      `js-scrolly` to the html element. Without it the section falls back to a
      plain vertical list: every screenshot visible, in its own frame, beside
      its own copy. Nothing is lost, it just does not move.
   2. REDUCED MOTION. Same fallback. A person who has asked their system for
      less movement should not be handed a rotating slab, and this mirrors Calm
      mode in the app.
   3. ASSISTIVE TECH. The pinned device is `aria-hidden`: it is a visual
      presentation of the steps, and its images carry empty alt. The
      description of each screen instead lives in that step's own copy, so a
      screen-reader user reads the same information in the same order.
   ========================================================================= */

.scrolly {
  padding-block: clamp(56px, 7vw, 96px);
}

.scrolly-inner {
  display: grid;
  gap: 40px;
}

/* --- the fallback (no JS, or reduced motion) is the DEFAULT ------------- */

.scrolly-stage {
  display: none; /* only shown once the script opts in */
}

.step {
  padding-block: clamp(28px, 4vw, 44px);
}

.step-fallback {
  margin-top: 22px;
}

/* --- enhanced ---------------------------------------------------------- */

.js-scrolly .scrolly-stage {
  display: block;
}

/* The inline frame that each step carries for the fallback is redundant once
   the pinned device exists. */
.js-scrolly .step-fallback {
  display: none;
}

@media (min-width: 900px) {
  .js-scrolly .scrolly-inner {
    grid-template-columns: 1fr 1.05fr;
    gap: clamp(40px, 5vw, 80px);
    align-items: start;
  }

  /* Stage on the right, copy on the left.

     The pinned box is a full viewport tall and centres its contents, rather
     than the stage being pinned at a computed offset. That keeps the device
     optically centred on a laptop and on a tall display alike, without the
     offset needing to know how tall the device happens to be at this width. */
  .js-scrolly .scrolly-stage {
    order: 2;
    position: sticky;
    top: 48px; /* the global bar */
    height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-self: start;
  }

  .js-scrolly .scrolly-steps {
    order: 1;
  }

  .js-scrolly .step {
    /* Each step owns a screenful, which is what gives the device time to
       finish one move before the next begins. */
    min-height: 78vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-block: 0;
  }
}

/* On a phone the device pins to the top and the copy runs underneath it. */
@media (max-width: 899px) {
  .js-scrolly .scrolly-stage {
    position: sticky;
    top: 60px;
    z-index: 2;
    padding-bottom: 12px;
    background: linear-gradient(var(--paper) 78%, transparent);
  }

  .band-dark .js-scrolly .scrolly-stage,
  .js-scrolly .band-dark .scrolly-stage {
    background: linear-gradient(var(--black) 78%, transparent);
  }

  .js-scrolly .step {
    min-height: 62vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/* --- the device -------------------------------------------------------- */

.ipad-wrap {
  position: relative;
  perspective: 1600px;
  perspective-origin: 50% 45%;
}

.ipad {
  position: relative;
  margin-inline: auto;
  max-width: 720px;
  padding: 2.1%;
  border-radius: 30px;
  background: linear-gradient(150deg, #545458 0%, #2c2c2e 42%, #1c1c1e 100%);
  box-shadow: 0 2px 0 rgba(255, 255, 255, 0.22) inset,
    0 30px 70px -28px rgba(0, 0, 0, 0.65);
  transform-style: preserve-3d;
  /* The single transition that every attitude change rides on. Long and
     heavily eased so a fast scroll still reads as one continuous move. */
  transition: transform 1100ms cubic-bezier(0.22, 0.61, 0.24, 1);
  will-change: transform;
}

.ipad-screen {
  position: relative;
  aspect-ratio: 1400 / 965;
  border-radius: 16px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55);
}

.ipad-screen img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.015);
  transition: opacity 620ms var(--ease), transform 1100ms var(--ease);
}

.ipad-screen img.is-active {
  opacity: 1;
  transform: none;
}

/* Camera, on the long edge, where an iPad in landscape has it. */
.ipad::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0.85%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 50%;
  background: #0b0b0c;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.09);
}

/* --- attitudes --------------------------------------------------------
   One per step. Chosen so the screen never turns far enough to become
   unreadable: a communication board that a reader cannot make out is a
   picture of nothing. Nothing here rotates on Z past a few degrees, and
   nothing flips, because the screenshots are landscape and a 90-degree roll
   would show a sideways board that does not exist in the product.
   -------------------------------------------------------------------- */

.ipad[data-attitude='front'] {
  transform: rotateY(0deg) rotateX(0deg) scale(1);
}
.ipad[data-attitude='turn-left'] {
  transform: perspective(1600px) rotateY(-19deg) rotateX(5deg) scale(1.01);
}
.ipad[data-attitude='zoom'] {
  transform: scale(1.22) translateY(1%);
}
.ipad[data-attitude='turn-right'] {
  transform: perspective(1600px) rotateY(19deg) rotateX(-6deg) scale(1.01);
}
.ipad[data-attitude='tilt-back'] {
  transform: perspective(1600px) rotateX(15deg) scale(0.97);
}
.ipad[data-attitude='roll'] {
  transform: rotateZ(-5deg) scale(1.04);
}
.ipad[data-attitude='roll-right'] {
  transform: rotateZ(5deg) scale(1.04);
}
.ipad[data-attitude='lean'] {
  transform: perspective(1600px) rotateY(-12deg) rotateZ(3deg) scale(1.06);
}
.ipad[data-attitude='pull-back'] {
  transform: scale(0.9);
}
/* The revolve. A full turn that lands flat on the front again, so it is a
   flourish rather than a state you can get stuck inside. */
.ipad[data-attitude='revolve'] {
  transform: perspective(1600px) rotateY(360deg) scale(1.02);
}

/* --- step copy --------------------------------------------------------- */

.step .eyebrow {
  font-size: 17px;
}

.step h3 {
  font-size: clamp(26px, 3vw, 42px);
  line-height: 1.08;
}

/* The step being read is at full strength; the others recede. Opacity only —
   the text never moves, so nothing reflows while somebody is reading it. */
.js-scrolly .step {
  opacity: 0.32;
  transition: opacity 480ms var(--ease);
}

.js-scrolly .step.is-current {
  opacity: 1;
}

/* --- progress rail ----------------------------------------------------- */

.scrolly-progress {
  display: none;
}

.js-scrolly .scrolly-progress {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-top: 20px;
  flex-wrap: wrap;
}

.scrolly-progress span {
  width: 22px;
  height: 4px;
  border-radius: 2px;
  background: var(--rail);
  transition: background 380ms var(--ease);
}

.band-dark .scrolly-progress span {
  background: rgba(255, 255, 255, 0.22);
}

.scrolly-progress span.is-on {
  background: var(--blue);
}

.band-dark .scrolly-progress span.is-on {
  background: var(--blue-dark);
}

/* --- the two non-negotiable opt-outs ----------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* Back to the plain list: no pinning, no transforms, no cross-fade. */
  .js-scrolly .scrolly-stage {
    display: none;
  }
  .js-scrolly .step-fallback {
    display: block;
  }
  .js-scrolly .scrolly-inner {
    grid-template-columns: 1fr;
  }
  .js-scrolly .step {
    min-height: 0;
    opacity: 1;
    display: block;
    padding-block: clamp(28px, 4vw, 44px);
  }
  .ipad,
  .ipad-screen img {
    transition: none;
  }
}

/* =========================================================================
   Sequence, second pass: hero framing, side switching, companion devices,
   assistive hardware, the Skyle housing, and the full-bleed takeover.
   ========================================================================= */

/* The hero screenshot now sits in the same iPad frame as the sequence, so
   the page opens on the device it is about. */
.hero-media .ipad {
  max-width: 860px;
}

/* --- the stage can sit on either side ---------------------------------- */

@media (min-width: 900px) {
  .js-scrolly .scrolly--left .scrolly-stage {
    order: 1;
  }
  .js-scrolly .scrolly--left .scrolly-steps {
    order: 2;
  }
}

/* Companion devices and hardware overflow the device on purpose; clip the
   section on x only. `clip`, not `hidden`: hidden would break the sticky
   stage, clip does not. */
.scrolly {
  overflow-x: clip;
}

/* --- extra attitudes --------------------------------------------------- */

.ipad[data-attitude='back-up'] {
  transform: scale(0.84) translateY(-5%);
}

/* --- companion devices (cross-platform step) --------------------------- */

.side-device {
  position: absolute;
  opacity: 0;
  transform: translateY(16px) scale(0.94);
  transition: opacity 640ms var(--ease), transform 900ms var(--ease);
  pointer-events: none;
}

.scrolly-stage[data-mode='trio'] .side-device {
  opacity: 1;
  transform: none;
}

.scrolly-stage[data-mode='trio'] .side-device.phone {
  transition-delay: 120ms;
}

.scrolly-stage[data-mode='trio'] .side-device.laptop {
  transition-delay: 40ms;
}

/* Phone: portrait, bottom-left, in front.

   Drawn to iPhone proportions rather than as a generic rounded rectangle.
   The details that actually make the silhouette read as an iPhone, in the
   order they matter at this size:

     - the corner geometry. A single border-radius percentage would give an
       ellipse on a 1:2.17 box, so the horizontal and vertical radii are set
       separately to land on a true circular corner (0.16w either way).
     - the Dynamic Island, which is the one shape nothing else has.
     - an even hairline bezel: iPhone bezels are the same width all round,
       unlike the older chin-and-forehead phones.
     - the titanium rail catching light along the top edge, and the side
       buttons breaking the outline.
     - the home indicator.

   The screen is a real portrait capture from an iPhone simulator, not the
   landscape iPad shot cropped, so the app inside is laid out the way it
   really is on a phone.
   -------------------------------------------------------------------- */
.side-device.phone {
  width: 20.5%;
  /* 1206 x 2622 device pixels */
  aspect-ratio: 1206 / 2622;
  left: -6%;
  bottom: -8%;
  z-index: 3;
  /* No padding: a percentage padding resolves against the CONTAINING BLOCK's
     width (.ipad-wrap), not this element's, so 1.9% here rendered a bezel of
     9.3% of the phone's own width -- about four times an iPhone's. The screen
     is inset instead, where percentages do resolve against the phone. */
  /* horizontal 16% of width; vertical the same distance expressed against
     height (0.16w / 2.174w), which is what keeps the corner circular. */
  border-radius: 16% / 7.36%;
  background: linear-gradient(148deg, #6f7076 0%, #3a3a3c 30%, #1d1d1f 62%, #48484c 100%);
  box-shadow: 0 0 0 0.6px rgba(0, 0, 0, 0.55),
    0 1.5px 0 rgba(255, 255, 255, 0.34) inset,
    0 26px 46px -18px rgba(0, 0, 0, 0.6);
}

.side-device.phone .phone-screen {
  /* An even 2.4%-of-width bezel all round. Left and right resolve against the
     phone's width; top and bottom resolve against its height, so they are
     scaled by the 1206:2622 aspect to come out the same thickness. */
  position: absolute;
  inset: 1.1% 2.4%;
  /* body radius (16% of width) less the bezel, expressed against the screen */
  border-radius: 14.3% / 6.4%;
  overflow: hidden;
  background: #000;
}

.side-device.phone img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* No Dynamic Island or home-indicator overlay here on purpose: the screen is
   a real iOS capture at exactly the screen's aspect ratio, so it already
   contains both, drawn by the system. Adding our own would double them. */

/* Side buttons: action button and volume pair on the left, power on the
   right. Small, but they are most of what makes the outline read correctly. */
.side-device.phone .btn-l,
.side-device.phone .btn-r {
  position: absolute;
  width: 1.6%;
  background: linear-gradient(#6f7076, #3a3a3c);
  border-radius: 1px;
}

.side-device.phone .btn-l {
  left: -1.4%;
  border-radius: 1px 0 0 1px;
}

.side-device.phone .btn-l.b1 { top: 15%; height: 4.6%; }
.side-device.phone .btn-l.b2 { top: 23%; height: 8.4%; }
.side-device.phone .btn-l.b3 { top: 33.5%; height: 8.4%; }

.side-device.phone .btn-r {
  right: -1.4%;
  top: 26%;
  height: 12.4%;
  border-radius: 0 1px 1px 0;
}

/* Laptop: behind and to the right. */
.side-device.laptop {
  width: 62%;
  right: -14%;
  bottom: -4%;
  z-index: 1;
}

.side-device.laptop .laptop-screen {
  aspect-ratio: 16 / 10;
  padding: 2.4%;
  border-radius: 12px 12px 0 0;
  background: linear-gradient(150deg, #545458 0%, #2c2c2e 42%, #1c1c1e 100%);
  box-shadow: 0 2px 0 rgba(255, 255, 255, 0.2) inset,
    0 24px 50px -20px rgba(0, 0, 0, 0.5);
}

.side-device.laptop .laptop-screen > div {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  overflow: hidden;
  background: #000;
}

.side-device.laptop img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.side-device.laptop .laptop-base {
  height: 13px;
  margin-inline: -4%;
  border-radius: 0 0 14px 14px;
  background: linear-gradient(#3a3a3c, #1c1c1e);
  box-shadow: 0 10px 22px -12px rgba(0, 0, 0, 0.55);
}

.side-device.laptop .laptop-base::before {
  content: '';
  display: block;
  width: 14%;
  height: 5px;
  margin-inline: auto;
  border-radius: 0 0 8px 8px;
  background: rgba(255, 255, 255, 0.14);
}

/* --- assistive switches (multiple-inputs step) --------------------------
   Original illustrations, deliberately NOT manufacturers' product photos:
   those are copyrighted marketing assets. Drawn flat, in the site's own
   register, at the real proportions of the hardware types they stand for —
   the big domed button, the feather-light lever switch, the light-ring smart
   button, sip-and-puff, and the grasp switch.
   -------------------------------------------------------------------- */

.switchset {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.switchset .sw {
  position: absolute;
  opacity: 0;
  transform: translateY(14px) scale(0.9);
  transition: opacity 520ms var(--ease), transform 760ms var(--ease);
}

.scrolly-stage[data-mode='switches'] .sw {
  opacity: 1;
  transform: none;
}

.scrolly-stage[data-mode='switches'] .sw:nth-child(2) { transition-delay: 90ms; }
.scrolly-stage[data-mode='switches'] .sw:nth-child(3) { transition-delay: 180ms; }
.scrolly-stage[data-mode='switches'] .sw:nth-child(4) { transition-delay: 270ms; }
.scrolly-stage[data-mode='switches'] .sw:nth-child(5) { transition-delay: 360ms; }

.sw svg {
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.18));
}

.sw-dome-lg { width: 21%; left: -7%; top: 6%; }
.sw-dome-sm { width: 13%; left: -2%; bottom: 2%; }
.sw-ring    { width: 16%; right: -5%; top: -2%; }
.sw-lever   { width: 17%; right: -8%; bottom: 26%; }
.sw-puff    { width: 15%; right: 4%; bottom: -8%; }

/* --- the Skyle housing (eye-gaze step) ----------------------------------
   The iPad gains the matte housing an eye tracker adds around it, with the
   infrared module bar under the screen. Padding is animatable, so the frame
   visibly thickens as the step arrives and thins as it leaves.
   -------------------------------------------------------------------- */

.ipad .skyle-bar {
  height: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  transition: height 700ms var(--ease), margin 700ms var(--ease);
}

.scrolly-stage[data-mode='skyle'] .ipad {
  padding: 3.4% 3.4% 0;
  background: linear-gradient(150deg, #6e6e73 0%, #3a3a3c 45%, #2c2c2e 100%);
}

.scrolly-stage[data-mode='skyle'] .ipad .skyle-bar {
  height: 44px;
  margin-top: 2%;
}

.skyle-bar i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #101012;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.07),
    0 0 10px 1px rgba(210, 60, 60, 0.35);
}

.skyle-bar i:nth-child(2) {
  width: 14px;
  height: 14px;
}

/* --- the takeover ------------------------------------------------------
   After the pinned sequences, the device gets the whole width of the site
   to itself. A dedicated section rather than a scale inside the pinned
   column: growing the device over the text column it sits beside would
   cover the words somebody is reading, and a takeover that fights the
   reader is not a flourish worth having.
   -------------------------------------------------------------------- */

.takeover {
  padding-inline: 0;
}

.takeover .ipad {
  max-width: min(1180px, 96vw);
  margin-inline: auto;
}

.takeover-copy {
  margin-bottom: clamp(36px, 5vw, 64px);
}

@media (max-width: 899px) {
  .sw-dome-lg { left: -3%; }
  .sw-lever,
  .sw-ring { right: -3%; }
  .side-device.laptop { right: -8%; }
  .side-device.phone { left: -2%; }
}

@media (prefers-reduced-motion: reduce) {
  .side-device,
  .switchset .sw {
    transition: none;
  }
  .ipad .skyle-bar {
    transition: none;
  }
}

/* =========================================================================
   Contextual props
   =========================================================================

   Each of these steps gets its own small cast of objects around the device,
   animated to act out what the copy is describing rather than to decorate it.
   Vibration shows a finger travelling the board with the screen buzzing under
   it; Voice shows sound leaving the device; Visual supports draws its own
   arrow. If an animation here does not mean something, it should not be here.

   All drawn, not photographed: flat vector holds the page's register, and
   nothing on a commercial site should depend on stock imagery it has no
   licence for.

   Animations are PAUSED until their step is current, so fifteen prop sets do
   not all run at once behind the scroll.
   ========================================================================= */

.props {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 4;
}

.prop-set {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 520ms var(--ease);
}

.prop-set * {
  animation-play-state: paused;
}

.scrolly-stage[data-mode='editing'] .prop-set[data-for='editing'],
.scrolly-stage[data-mode='functions'] .prop-set[data-for='functions'],
.scrolly-stage[data-mode='vibration'] .prop-set[data-for='vibration'],
.scrolly-stage[data-mode='voice'] .prop-set[data-for='voice'],
.scrolly-stage[data-mode='symbols'] .prop-set[data-for='symbols'],
.scrolly-stage[data-mode='identity'] .prop-set[data-for='identity'],
.scrolly-stage[data-mode='maps'] .prop-set[data-for='maps'],
.scrolly-stage[data-mode='remnant'] .prop-set[data-for='remnant'],
.scrolly-stage[data-mode='school'] .prop-set[data-for='school'] {
  opacity: 1;
  visibility: visible;
}

.scrolly-stage[data-mode='editing'] .prop-set[data-for='editing'] *,
.scrolly-stage[data-mode='functions'] .prop-set[data-for='functions'] *,
.scrolly-stage[data-mode='vibration'] .prop-set[data-for='vibration'] *,
.scrolly-stage[data-mode='voice'] .prop-set[data-for='voice'] *,
.scrolly-stage[data-mode='symbols'] .prop-set[data-for='symbols'] *,
.scrolly-stage[data-mode='identity'] .prop-set[data-for='identity'] *,
.scrolly-stage[data-mode='maps'] .prop-set[data-for='maps'] *,
.scrolly-stage[data-mode='remnant'] .prop-set[data-for='remnant'] *,
.scrolly-stage[data-mode='school'] .prop-set[data-for='school'] * {
  animation-play-state: running;
}

.prop {
  position: absolute;
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.16));
}

.prop svg {
  width: 100%;
  height: auto;
  display: block;
}

/* --- Editing: a pointer picks a colour, the swatch row answers ---------- */

.p-palette { width: 26%; left: -11%; bottom: 16%; }
.p-cursor  { width: 7%;  left: 2%;  bottom: 30%; animation: cursor-pick 4.2s var(--ease) infinite; }

@keyframes cursor-pick {
  0%, 8%    { transform: translate(0, 0); }
  26%, 40%  { transform: translate(-72%, 44%); }
  58%, 72%  { transform: translate(-24%, 44%); }
  90%, 100% { transform: translate(0, 0); }
}

.p-palette .sw-chip { transform-origin: center; animation: chip-lift 4.2s var(--ease) infinite; }
.p-palette .sw-chip:nth-child(2) { animation-delay: 1.4s; }
.p-palette .sw-chip:nth-child(3) { animation-delay: 2.8s; }

@keyframes chip-lift {
  0%, 12%, 34%, 100% { transform: translateY(0) scale(1); }
  20%, 28%           { transform: translateY(-14%) scale(1.12); }
}

/* --- Functions: three chips fire in order, top to bottom ---------------- */

.p-stack { width: 30%; right: -13%; top: 20%; }
.p-stack .fn { animation: fn-fire 3.9s var(--ease) infinite; transform-origin: left center; }
.p-stack .fn:nth-child(2) { animation-delay: 0.55s; }
.p-stack .fn:nth-child(3) { animation-delay: 1.1s; }

@keyframes fn-fire {
  0%, 6%    { transform: translateX(14%); opacity: 0.35; }
  14%, 40%  { transform: translateX(0); opacity: 1; }
  56%, 100% { transform: translateX(0); opacity: 0.5; }
}

/* --- Vibration: a finger travels the board, the screen buzzes ----------- */

.p-hand { width: 17%; left: 6%; bottom: 8%; animation: hand-sweep 5.4s var(--ease) infinite; }

@keyframes hand-sweep {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(150%, -34%); }
  50%  { transform: translate(310%, -8%); }
  75%  { transform: translate(180%, -46%); }
  100% { transform: translate(0, 0); }
}

/* The rings sit at the fingertip and pulse on the same clock. */
.p-ring {
  width: 15%;
  left: 8%;
  bottom: 14%;
  animation: hand-sweep 5.4s var(--ease) infinite;
}

.p-ring circle { animation: ring-out 1.35s ease-out infinite; transform-origin: 50% 50%; }
.p-ring circle:nth-child(2) { animation-delay: 0.45s; }
.p-ring circle:nth-child(3) { animation-delay: 0.9s; }

@keyframes ring-out {
  0%   { transform: scale(0.3); opacity: 0.55; }
  100% { transform: scale(1.5); opacity: 0; }
}

/* The device itself buzzes. Applied to the SCREEN, not the frame: the frame
   carries the step's attitude transform and animating it would fight that. */
.scrolly-stage[data-mode='vibration'] .ipad-screen {
  animation: buzz 0.13s linear infinite;
}

@keyframes buzz {
  0%, 100% { transform: translate(0, 0); }
  25%      { transform: translate(0.9px, -0.5px); }
  50%      { transform: translate(-0.7px, 0.6px); }
  75%      { transform: translate(0.5px, 0.7px); }
}

/* --- Voice: sound leaves the device, a meter answers -------------------- */

.p-waves { width: 16%; left: -8%; top: 34%; }
.p-waves path { animation: wave-pulse 2.1s ease-out infinite; transform-origin: 8% 50%; }
.p-waves path:nth-child(2) { animation-delay: 0.28s; }
.p-waves path:nth-child(3) { animation-delay: 0.56s; }

@keyframes wave-pulse {
  0%, 100% { opacity: 0.18; transform: scale(0.88); }
  40%      { opacity: 1; transform: scale(1); }
}

.p-meter { width: 17%; right: -8%; bottom: 22%; }
.p-meter rect { animation: eq 1s ease-in-out infinite; transform-origin: 50% 100%; }
.p-meter rect:nth-child(2) { animation-delay: 0.16s; }
.p-meter rect:nth-child(3) { animation-delay: 0.32s; }
.p-meter rect:nth-child(4) { animation-delay: 0.1s; }
.p-meter rect:nth-child(5) { animation-delay: 0.4s; }

@keyframes eq {
  0%, 100% { transform: scaleY(0.35); }
  50%      { transform: scaleY(1); }
}

/* --- Symbols: picture cards drift in orbit ------------------------------ */

.p-sym { width: 12%; animation: drift 6.5s ease-in-out infinite; }
.p-sym-1 { left: -8%;  top: 12%; }
.p-sym-2 { right: -7%; top: 26%; animation-delay: 0.9s; }
.p-sym-3 { left: -6%;  bottom: 16%; animation-delay: 1.8s; }
.p-sym-4 { right: -5%; bottom: 8%; animation-delay: 2.7s; }

@keyframes drift {
  0%, 100% { transform: translateY(0) rotate(-4deg); }
  50%      { transform: translateY(-14%) rotate(4deg); }
}

/* --- Identity: a passport card, and the favourites that hang off it ----- */

.p-card { width: 27%; left: -12%; top: 22%; animation: card-breathe 5s ease-in-out infinite; }

@keyframes card-breathe {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  50%      { transform: translateY(-6%) rotate(-1deg); }
}

.p-tag { width: 11%; animation: tag-pop 4.4s var(--ease) infinite; }
.p-tag-1 { right: -6%; top: 30%; }
.p-tag-2 { right: -9%; top: 48%; animation-delay: 0.5s; }
.p-tag-3 { right: -4%; top: 66%; animation-delay: 1s; }

@keyframes tag-pop {
  0%, 4%    { transform: scale(0.6); opacity: 0; }
  14%, 74%  { transform: scale(1); opacity: 1; }
  88%, 100% { transform: scale(0.9); opacity: 0; }
}

/* --- Visual supports: one node's timer hands off to the next -----------
   The screen already shows the map, so the prop shows the thing the map
   screenshot cannot: a countdown draining, then passing to the next node.
   -------------------------------------------------------------------- */

.p-timer { width: 15%; }
.p-timer-1 { right: -9%; top: 16%; }
.p-timer-2 { right: -9%; top: 56%; }

.p-handoff { width: 11%; right: -7%; top: 40%; animation: handoff 5.2s var(--ease) infinite; }

/* 251 is the circumference of r=40, so the dial drains a full turn. */
.p-timer .dial { stroke-dasharray: 251; stroke-dashoffset: 0; }
.p-timer-1 .dial { animation: drain 5.2s linear infinite; }
.p-timer-2 .dial { animation: drain 5.2s linear infinite; animation-delay: 2.6s; }

@keyframes drain {
  0%       { stroke-dashoffset: 0; opacity: 1; }
  48%      { stroke-dashoffset: 251; opacity: 1; }
  50%, 100% { stroke-dashoffset: 251; opacity: 0.25; }
}

@keyframes handoff {
  0%, 40%   { opacity: 0; transform: translateX(-30%); }
  50%, 62%  { opacity: 1; transform: translateX(0); }
  74%, 100% { opacity: 0; transform: translateX(30%); }
}

/* --- Remnant Book: the day's keepsakes settle --------------------------- */

.p-keep { width: 13%; animation: keep-float 7s ease-in-out infinite; }
.p-keep-1 { left: -9%;  top: 20%; }
.p-keep-2 { right: -8%; top: 36%; animation-delay: 1.6s; }
.p-keep-3 { left: -5%;  bottom: 14%; animation-delay: 3.2s; }

@keyframes keep-float {
  0%, 100% { transform: translateY(0) rotate(-5deg); }
  50%      { transform: translateY(-18%) rotate(5deg); }
}

/* --- School: a document becomes sections and a quiz --------------------- */

.p-doc { width: 17%; left: -9%; top: 26%; animation: doc-nudge 5.2s var(--ease) infinite; }

@keyframes doc-nudge {
  0%, 100% { transform: translate(0, 0) rotate(-4deg); }
  50%      { transform: translate(8%, -6%) rotate(-1deg); }
}

.p-out { width: 20%; right: -10%; animation: out-in 5.2s var(--ease) infinite; }
.p-out-1 { top: 24%; }
.p-out-2 { top: 44%; animation-delay: 0.5s; }
.p-out-3 { top: 64%; animation-delay: 1s; }

@keyframes out-in {
  0%, 12%   { transform: translateX(22%); opacity: 0; }
  30%, 78%  { transform: translateX(0); opacity: 1; }
  94%, 100% { transform: translateX(22%); opacity: 0; }
}

/* Calm mode: the props still appear, so the meaning survives, but nothing
   moves and the device does not buzz. */
@media (prefers-reduced-motion: reduce) {
  .prop-set *,
  .scrolly-stage[data-mode='vibration'] .ipad-screen {
    animation: none !important;
  }
  .prop-set {
    transition: none;
  }
}

@media (max-width: 899px) {
  .p-palette { left: -6%; }
  .p-stack, .p-meter, .p-timer, .p-handoff, .p-out { right: -6%; }
  .p-card { left: -7%; }
}

/* ==========================================================================
   Sign in
   Same Super account as the app. The nav item is a real link to /lms/ when
   the script is blocked; these styles dress both that link and the dialog
   that upgrades it.
   ========================================================================== */

/* Pushed to the right-hand end of the bar, and separated by a hairline so it
   reads as a different KIND of thing from the page links beside it — not by
   colour, which the accessibility page rules out as the only signal. */
.globalnav-auth {
  margin-inline-start: 6px;
}

.globalnav-auth a,
.globalnav-auth button {
  display: inline-flex;
  align-items: center;
  /* The 44px floor the site holds itself to, small type and all. */
  height: 44px;
  padding-inline: 16px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--ink);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--paper);
  cursor: pointer;
}

/* The bar's links sit at 0.68, and the pill inherited it: in dark that turns
   the #f5f5f7 pill a flat mid-grey with greyed text, and the account action
   looks switched off. Light keeps the pill as it always was. */
:root:not([data-theme="light"]) .globalnav-auth a,
:root:not([data-theme="light"]) .globalnav-auth button {
  opacity: 1;
}

/* Focus as hover. `.globalnav-list a:focus-visible` (the page links' wash)
   reaches the "Sign in" pill too and, being more specific than the pill's
   own rule, swapped its ink fill for the wash under the pill's --paper text:
   the label all but vanished, in both themes, the moment it had keyboard
   focus. These selectors match that one's weight and come later. */
.globalnav-auth a:hover,
.globalnav-auth button:hover,
.globalnav-auth a:focus-visible,
.globalnav-auth button:focus-visible {
  text-decoration: none;
  background: var(--ink-hover);
  color: var(--paper);
}

/* ---------------------------------------------------------------- language
   The picker is a plain list of links, one per language, all pointing at the
   page you are already on. It has to keep working in the situation it exists
   for: somebody who has landed in a language they cannot read and needs to get
   out. So no script, no custom widget, and the current language is marked by
   weight and a bullet rather than by colour alone. */
.langpicker {
  margin-top: clamp(28px, 4vw, 44px);
  padding-top: clamp(24px, 3vw, 32px);
  /* No rule of its own: the footer grid's bottom hairline already separates
     it, and two rules with nothing between read as a stray double line on
     the white footer. */
}

.langpicker h4 {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink);
  margin: 0 0 12px;
}

.langpicker ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 2px 4px;
}

.langpicker a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 12px;
  border-radius: var(--r-pill);
  font-size: 13px;
  color: var(--ink-2);
}

.langpicker a:hover {
  color: var(--ink);
  background: var(--wash);
  text-decoration: none;
}

/* The language you are reading. Weight and a leading bullet, so the mark is
   not carried by tone alone -- the same rule the rest of the site follows. */
.langpicker a[aria-current='true'] {
  color: var(--ink);
  font-weight: 600;
}

.langpicker a[aria-current='true']::before {
  content: '\2022';
  margin-inline-end: 6px;
}

/* --------------------------------------------------------- sign-up mode
   The dialog is one form in two modes. Only the confirmation row and the
   labels change, so there is a single focus trap, a single Escape path and
   one place the wording lives. */


/* ------------------------------------------------- account & shop */

/* The circle in the navigation. A link, because it goes to a page — it has to
   middle-click and it has to read as a link. Sized to the nav's other controls
   so the bar keeps one rhythm rather than growing a taller item. */
.auth-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--blue);
  color: var(--on-blue);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  overflow: hidden;
  flex: 0 0 auto;
  text-decoration: none;
}

/* The avatar sits in the nav list, so `.globalnav-list a` reaches it and wins
   on specificity: it was handing the circle a 44px height, 14px of side
   padding and 0.68 opacity, which is what turned it into a translucent pill.
   Restated here at matching specificity rather than with !important, and with
   50% rather than a large pixel radius so the shape follows the box instead of
   depending on it staying square. Focus too: `.globalnav-list a:focus-visible`
   painted the page links' wash over the blue circle. */
.globalnav-list .auth-avatar,
.globalnav-list .auth-avatar:hover,
.globalnav-list .auth-avatar:focus-visible {
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  opacity: 1;
  background: var(--blue);
}

.globalnav-list .auth-avatar:hover {
  filter: brightness(1.08);
}

.auth-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Focus has to be visible ON the circle, and the circle is the same colour as
   the site's focus ring, so it gets an offset halo rather than a border. */
.auth-avatar:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

.globalnav-auth {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* -------------------------------------------------------- account page */

.acct-hero .wrap { padding-top: 8px; }

.acct-id {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 18px;
}

.acct-face {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: var(--r-pill);
  background: var(--blue);
  color: var(--on-blue);
  font-size: 26px;
  font-weight: 600;
  overflow: hidden;
  flex: 0 0 auto;
}

.acct-face img { width: 100%; height: 100%; object-fit: cover; display: block; }

.acct-email { color: var(--ink-2); margin: 2px 0 0; }

/* An account with no name shows its address as the heading, in display
   type: one long word, which pushed a phone's page sideways (2026-10-26).
   It breaks anywhere instead, and the column may shrink inside the row. */
.acct-id > div { min-width: 0; }
.acct-id .display,
.acct-email { overflow-wrap: anywhere; }

.acct-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  align-items: stretch;
}

/* With no band colour behind a section, the gap between its heading and its
   cards is the only structure left: give it room. */
.subhead + .acct-cards { margin-top: 18px; }

.acct-card {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: clamp(22px, 2.4vw, 30px);
  display: flex;
  flex-direction: column;
}

/* A card whose state could not be read is drawn quieter, never as an offer:
   the one thing it must not look like is "you have nothing, buy something".
   Light: grey on the white ground. Dark: the ground itself inside the
   card's hairline, an outline where the other cards are filled. */
.acct-card.is-unknown { background: var(--card-quiet); }

.acct-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.acct-card h3 { font-size: 22px; margin: 0; }

.acct-card-link { font-size: 14px; }

.acct-tier {
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 14px 0 2px;
}

.acct-expiry, .acct-state, .acct-from, .acct-progress-text {
  font-size: 14px;
  color: var(--ink-2);
  margin: 0;
}

.acct-expiry.is-past { color: var(--error); }

.acct-from { margin-top: 10px; }

.acct-buy, .acct-open { margin-top: auto; align-self: flex-start; }
.acct-buy { margin-top: 18px; }
.acct-open { margin-top: 16px; }

/* Progress as a bar AND as words. The bar alone would carry the number in
   colour and width only, which is exactly what this site's accessibility page
   promises it never does. */
.acct-bar {
  margin-top: 10px;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--track);
  overflow: hidden;
}

.acct-bar > span {
  display: block;
  height: 100%;
  background: var(--blue);
  border-radius: inherit;
}

/* ---------------------------------------------------------------- shop */

.shop-lede {
  color: var(--ink-2);
  max-width: 62ch;
  margin: 0 0 22px;
}

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

.plan .btn { margin-top: auto; align-self: flex-start; }

/* The message after choosing a tier. Sits inside the card it belongs to, so
   there is no doubt which tier it is talking about. */
.shop-note {
  margin: 14px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--raised);
  border-radius: var(--r-sm);
  padding: 12px 14px;
}

/* --------------------------------------------------------- specialists
   The public Super Specialists directory, and the editor a verified
   specialist sees for their own page. Everything here is drawn by
   assets/js/specialists.js at run time, so none of it exists in the HTML. */
.spec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: clamp(14px, 2vw, 20px);
}

.spec-card {
  display: block;
  padding: 18px 18px 16px;
  border: 1px solid var(--rule);
  border-radius: var(--r-lg, 22px);
  background: var(--card);
  color: inherit;
  text-decoration: none;
  transition: transform 180ms var(--ease), box-shadow 180ms var(--ease),
    border-color 180ms var(--ease);
}

/* On black a shadow does not show, so in the dark theme the lifted card also
   brightens its edge (--rule-hover; the same as --rule in the light one). */
.spec-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lift);
  border-color: var(--rule-hover);
}

.spec-card-head { display: flex; align-items: center; gap: 12px; }
.spec-card-who { min-width: 0; }
.spec-card-who strong { display: block; font-size: 16px; font-weight: 700; }

.spec-avatar {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--raised);
  font-weight: 800;
  font-size: 17px;
  color: var(--blue);
}

.spec-avatar img { width: 100%; height: 100%; object-fit: cover; }
.spec-avatar-lg { width: 72px; height: 72px; font-size: 27px; }

.spec-headline { font-size: 13.5px; color: var(--ink-2); }
.spec-line { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-2); }
.spec-place { font-weight: 600; }
.spec-km { color: var(--blue); font-weight: 700; }

.spec-tags { margin: 12px 0 0; display: flex; flex-wrap: wrap; gap: 6px; }

.spec-tag {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--raised);
  color: var(--ink-2);
}

.spec-empty {
  padding: 28px 0;
  text-align: center;
  color: var(--ink-2);
}

/* ---- one person's page ---- */
.spec-back { display: inline-block; margin-bottom: 18px; }
.spec-detail-head { display: flex; align-items: center; gap: 18px; }
.spec-name { margin: 0; font-size: clamp(1.6rem, 3.6vw, 2.4rem); letter-spacing: -0.02em; }
.spec-bio { margin: 20px 0 0; max-width: 62ch; line-height: 1.6; }

.spec-facts {
  margin: 24px 0 0;
  display: grid;
  grid-template-columns: minmax(120px, max-content) 1fr;
  gap: 8px 20px;
  max-width: 62ch;
}

.spec-facts dt { font-weight: 700; font-size: 13.5px; color: var(--ink-2); }
.spec-facts dd { margin: 0; font-size: 14.5px; }

/* ---- the editor ---- */
.spec-editor { max-width: 560px; margin-inline: auto; }
.spec-editor-title { margin: 0 0 4px; font-size: 22px; }
.spec-editor-note { margin: 0 0 20px; font-size: 13.5px; color: var(--ink-2); }
.spec-field { margin-bottom: 14px; }

.spec-field label {
  display: block;
  margin-bottom: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
}

.spec-field input,
.spec-field textarea {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--control-line);
  border-radius: 10px;
  background: var(--field);
  color: var(--ink);
  font: inherit;
  font-size: 16px;  /* 16px stops iOS zooming the page on focus */
}

.spec-field textarea { min-height: 120px; resize: vertical; }

.spec-check {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 6px 0 16px;
  font-weight: 500;
  cursor: pointer;
}

.spec-check input { width: 18px; height: 18px; flex: none; }

.spec-actions { display: flex; align-items: center; gap: 16px; }
.spec-delete { color: var(--danger); }

.spec-status {
  margin: 12px 0 0;
  min-height: 1.4em;
  font-size: 13.5px;
  color: var(--ink-2);
}

/* -------------------------------------------------------------- pcards
   The Store's product cards. One card carries everything about the thing it
   is selling -- name, price, what you get -- so a reader never has to hold
   two columns in their head at once. Rendered by assets/js/shop.js. */
.pcards {
  list-style: none;
  margin: clamp(18px, 2.4vw, 26px) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(14px, 2vw, 20px);
  align-items: stretch;
}

/* One card should not stretch across the whole band like a banner. */
.pcards-one { grid-template-columns: minmax(260px, 420px); }

/* The Store's three columns: Free, SuperAAC, SuperVOCA side by side. Each
   column is a subgrid of four rows -- heading, intro, term switch, cards --
   so the three headings, the three intros and the first card of each start
   level, whatever the length of the text above them. The hosts shop.js fills
   are display: contents, so its switch and its card list are rows of the
   column themselves; Free has no switch, and its row 3 simply stays empty.
   Within a column the cards stack, one per row of the list: SuperAAC's three
   tiers run down the middle column. */
.shop-cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: auto auto auto 1fr;
  column-gap: clamp(20px, 3vw, 40px);
}
.shop-col {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  align-content: start;
}
.shop-col > [data-shop-free],
.shop-col > [data-shop-product] { display: contents; }
.shop-col > .subhead { grid-row: 1; margin-bottom: 8px; }
.shop-col > .shop-lede { grid-row: 2; margin-bottom: 0; }
.shop-col .pswitch { grid-row: 3; justify-self: start; margin-top: 18px; }
.shop-col .pcards {
  grid-row: 4;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
}
/* Room for the "Most popular" badge, which sits over its card's top edge. */
.shop-col .pcards { row-gap: clamp(20px, 2.4vw, 26px); }

/* Under a laptop's width three columns of cards are too narrow to read: they
   stack, in the same order, a band's worth of space between them. */
@media (max-width: 980px) {
  .shop-cols { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .shop-col { display: block; grid-row: auto; }
  .shop-col + .shop-col { margin-top: clamp(48px, 8vw, 72px); }
  .shop-col .pswitch { display: inline-flex; }
  .shop-col .pcards { max-width: 520px; }
}

.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 2.4vw, 28px);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg, 22px);
  background: var(--card);
}

/* The one most people want, lifted rather than recoloured -- a card that
   shouts is a card people distrust. */
.pcard-hi {
  border-color: var(--blue);
  box-shadow: var(--shadow-hi);
}

.pcard-badge {
  position: absolute;
  top: -11px;
  left: clamp(20px, 2.4vw, 28px);
  padding: 3px 11px;
  border-radius: 999px;
  background: var(--blue);
  color: var(--on-blue);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.pcard-name {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.pcard-price {
  margin: 8px 0 0;
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}

.pcard-note {
  margin: 6px 0 0;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-2);
}

.pcard-feats {
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 8px;
}

.pcard-feats li {
  position: relative;
  padding-left: 22px;
  font-size: 14px;
  line-height: 1.45;
}

.pcard-feats li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.52em;
  width: 9px;
  height: 5px;
  border-left: 2px solid var(--blue);
  border-bottom: 2px solid var(--blue);
  transform: rotate(-45deg);
}

/* Pushed to the bottom so buttons line up across cards of different heights.
 * The gap above goes on the LIST, not as a margin on the button -- a margin
 * there overrides `auto` and puts the button back under the last bullet, which
 * is where the three of them stopped lining up. */
.pcard-cta { margin-top: auto; align-self: flex-start; }
.pcard-feats { margin-bottom: 20px; }
/* A card with a note and no list (SuperVOCA's one plan) keeps the same air
   above its button that the list gives the others. */
.pcard-note + .pcard-cta { margin-top: 20px; }

/* A notice in a native <dialog> (training.html, "Available on December
   15th"): a card, centred over the dimmed page, in the theme's colours; on
   black a shadow alone gives it no edge, so a hairline rim does. The
   backdrop is a literal: ::backdrop does not take the page's tokens in every
   browser. */
.soon-dialog {
  width: min(420px, calc(100% - 40px));
  padding: 32px 28px 28px;
  border: 0;
  border-radius: var(--r-lg, 22px);
  background: var(--card);
  color: var(--ink);
  box-shadow: 0 0 0 1px var(--rule), 0 24px 60px rgba(0, 0, 0, 0.35);
  text-align: center;
}
.soon-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
.soon-dialog h2 {
  margin: 0 0 22px;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1.2;
  text-wrap: balance;
}
.soon-dialog form { margin: 0; }

/* ---- the term switch ---- */
.pswitch {
  display: inline-flex;
  padding: 4px;
  border-radius: 999px;
  background: var(--paper-2);
  gap: 2px;
}

/* 44px like every other target on the site: the licence panel already had
   it, the Store and the SuperAAC page's plans did not. */
.pswitch-b {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  padding: 8px 16px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

/* Chosen: a lifted segment and full-tone ink (the words "Monthly" / "5
   years" and aria-pressed say it too). Dark: #636366 on the #1d1d1f tray,
   the platform's own dark segmented control. */
.pswitch-b.is-on {
  background: var(--seg-on);
  color: var(--ink);
  box-shadow: var(--shadow-seg);
}

/* ---- Symbol on/off ------------------------------------------------------
 * A word with its symbol above it, laid out to the same numbers the app uses
 * in a board's writing area (lib/widgets/cell_widget.dart, _piece):
 * the picture is 1.9x the font size, 2px above the word, in padding of
 * 2px vertical and 4px horizontal.
 *
 * The whole thing is inline-block so symbolised words wrap and flow like the
 * text they replaced -- a block or a flex row would relayout the paragraph
 * around them, which is not what "turn symbols on" should do to a page.
 */
.sym-word {
  display: inline-block;
  vertical-align: bottom;   /* the app's WrapCrossAlignment.end */
  padding: 2px 4px;
  text-align: center;
  border-radius: 8px;
  line-height: inherit;
}

/* 1.9em is the app's ratio, clamped at both ends because a web page is not a
 * board. The app's writing area has one modest font size; this site has an
 * 88px display headline, where 1.9em is a 167px picture and the symbol stops
 * being a reading aid and becomes the page. The clamp keeps the app's
 * proportion through the body copy, where the reading actually happens. */
.sym-tile {
  display: block;
  width: clamp(18px, 1.9em, 56px);
  height: clamp(18px, 1.9em, 56px);
  margin: 0 auto 2px;
  border-radius: 6px;
}

/* Only when the caller asks for it. PAACs4Web does, because it cannot know
 * what is behind the symbol on somebody else's page. */
.sym-tile-fill { padding: 1px; }

/* The PAACs pictures are transparent line drawings made for a white ground:
 * on the dark theme their black outlines would vanish into the page, so each
 * picture sits on its own small white tile, as it does in the app. */
:root:not([data-theme="light"]) .sym-tile {
  background: #ffffff;
  padding: 1px;
}

.sym-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.sym-label { display: block; }

/* The floating switch, bottom right.
 *
 * It floats because it is a READING aid: somebody may want it four paragraphs
 * into an article, and in the navigation it would be off the top of the screen
 * by then -- and behind a hamburger on a phone.
 *
 * `inset-inline-end` rather than `right`. All sixteen languages the site ships
 * are left-to-right, so today it is the same declaration; if the site ever
 * ships Arabic or Hebrew the button moves to the corner that is the end of the
 * line there, instead of covering the start of every line.
 *
 * The safe-area insets keep it clear of the home indicator on a phone, where
 * the bottom 34pt belongs to the system and a button under it cannot be
 * pressed.
 */
.sym-toggle {
  position: fixed;
  inset-block-end: calc(20px + env(safe-area-inset-bottom, 0px));
  inset-inline-end: calc(20px + env(safe-area-inset-right, 0px));
  /* Under the sticky nav (9000) so an open mobile menu covers it, and far
     above page content, which never goes past 4. */
  z-index: 800;

  display: inline-flex;
  align-items: center;
  gap: 9px;
  /* 48px tall: a touch target for people whose aim this site is explicitly
     for. The WCAG 2.5.5 floor is 44. */
  min-height: 48px;
  padding: 0 20px 0 17px;
  border: 1px solid var(--float-line);
  border-radius: 980px;
  background: var(--card);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-float);
  -webkit-tap-highlight-color: transparent;
}

.sym-toggle:hover {
  background: var(--raised);
  box-shadow: var(--shadow-float-hover);
}

/* The site draws no focus ring of its own on this control, and a floating
   button is the last place to leave one to the browser's default. */
.sym-toggle:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 3px;
}

/* On: the pill inverts, ink fill and ground-coloured words -- near-black in
   the light theme, near-white in the dark one. */
.sym-toggle[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

.sym-toggle[aria-pressed="true"]:hover { background: var(--ink-strong); }

.sym-toggle-label { white-space: nowrap; }

.sym-toggle-dot {
  width: 15px;
  height: 15px;
  border-radius: 4px;
  border: 1.7px solid currentColor;
  position: relative;
  flex: none;
}

.sym-toggle[aria-pressed="true"] .sym-toggle-dot::after {
  content: "";
  position: absolute;
  inset: 2.5px;
  border-radius: 1.5px;
  background: currentColor;
}

/* Printed pages do not have a button on them. */
@media print { .sym-toggle { display: none; } }

/* Busy and failed states. A toggle that silently does nothing while a 500 kB
 * atlas downloads reads as broken, and one that stays "on" after the download
 * failed is a lie about what the reader is looking at. */
.sym-toggle[data-busy] { opacity: 0.6; cursor: progress; }
.sym-toggle[data-failed] { text-decoration: line-through; }

@media (prefers-reduced-motion: no-preference) {
  .sym-word { transition: background-color 0.15s ease; }
  .sym-toggle { transition: background-color 0.15s ease, box-shadow 0.2s ease, transform 0.15s ease; }
  .sym-toggle:hover { transform: translateY(-1px); }
  .sym-toggle:active { transform: translateY(0); }
}

/* ---- specialists: search, badges, map, reviews ------------------------- */

.spec-search { margin: 0 0 14px; }
.spec-search-input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--cool-control);
  border-radius: 12px;
  font: inherit;
  background: var(--field);
}
.spec-count { margin: 0 0 14px; opacity: .7; font-size: .9rem; }

.spec-badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
.spec-badge {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 700;
  background: var(--badge-bg);
  color: var(--badge-ink);
}
/* The one Super awards is drawn differently from the ones it merely checked.
   Rendering them identically would let "SLP" read as "certified by Super". */
.spec-badge-super {
  background: var(--badge-super-bg);
  color: var(--badge-super-ink);
  box-shadow: inset 0 0 0 1.2px currentColor;
}
.spec-badges-sm .spec-badge { font-size: .72rem; padding: 2px 7px; }

.spec-map { margin: 18px 0 6px; }
.spec-map iframe {
  width: 100%;
  height: 260px;
  border: 1px solid var(--cool-frame);
  border-radius: 14px;
  display: block;
}
.spec-map-link { display: inline-block; margin-top: 8px; font-size: .9rem; }

.spec-reviews { margin-top: 28px; }
.spec-reviews-title { font-size: 1.1rem; margin: 0 0 4px; }
.spec-reviews-avg { margin: 0 0 12px; opacity: .75; font-size: .9rem; }
.spec-review {
  padding: 12px 0;
  border-top: 1px solid var(--cool-line);
}
.spec-review-head {
  display: flex; gap: 10px; align-items: baseline; margin: 0 0 4px;
}
.spec-review-stars { letter-spacing: 1px; }
.spec-review-who { font-weight: 700; font-size: .9rem; }
.spec-review-text { margin: 0; line-height: 1.55; }

/* ----------------------------------------------------------- bookings
   Super Specialist sessions: the filters and the booking panel on the
   directory, the booking cards (booking.html, the account page, the practice
   page) and the practice page's forms. All drawn by assets/js at run time.
   Every state is said in words -- a ticked filter says "✓", a chosen time
   says "Chosen", a booking card carries its state word -- and colour only
   repeats it. Targets are 44px at least, as everywhere on this site. */

.spec-filters { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }

.spec-filter,
.slot-btn {
  min-width: 44px;
  min-height: 44px;
  padding: 8px 14px;
  border: 1px solid var(--control-line);
  background: var(--field);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  cursor: pointer;
}

.spec-filter { border-radius: var(--r-pill); }
.slot-btn { border-radius: var(--r-sm); }

.spec-filter[aria-pressed="true"],
.slot-btn[aria-pressed="true"] {
  background: var(--blue);
  border-color: var(--blue);
  color: var(--on-blue);
  font-weight: 600;
}

.spec-filter:focus-visible,
.slot-btn:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }

.spec-book-tag { background: var(--info-bg); color: var(--info-ink); }

.spec-sessions { margin-top: 28px; }
.spec-sessions-title { font-size: 1.1rem; margin: 0 0 4px; }
.spec-policy { margin: 0 0 12px; font-size: 14px; color: var(--ink-2); max-width: 62ch; }

.spec-offerings {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.spec-offering {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  background: var(--card);
}

.spec-offering-title { margin: 0; font-size: 17px; }
.spec-offering-text { margin: 0; font-size: 14px; line-height: 1.5; }
.spec-offering .btn { align-self: flex-start; margin-top: auto; }

.spec-book-panel {
  margin-top: 20px;
  padding: clamp(18px, 2.4vw, 26px);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  background: var(--card);
}

.spec-book-title { margin: 0; font-size: 20px; }
.spec-book-step { margin-top: 16px; }
.spec-book-h { margin: 0 0 6px; font-size: 16px; }
.spec-book-where { border: 0; padding: 0; margin: 0; }
.spec-book-where legend { font-weight: 700; font-size: 16px; margin-bottom: 6px; }
.spec-book-when { font-weight: 600; margin: 0 0 12px; }
.spec-help { margin: 6px 0 0; font-size: 13px; color: var(--ink-2); }
.spec-manage { padding-top: 4px; }

.slot-day { margin: 14px 0 6px; font-size: 14px; font-weight: 700; }
.slot-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---- booking cards ---- */
.bk-list-title { font-size: 17px; margin: 18px 0 10px; }

.bk-list {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

.bk-card {
  padding: clamp(18px, 2.2vw, 24px);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  background: var(--card);
  min-width: 0;
}

.bk-card-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }

.bk-state {
  margin: 0;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--raised);
  font-size: 14px;
  font-weight: 700;
}

.bk-card[data-state="confirmed"] .bk-state,
.bk-card[data-state="paid"] .bk-state,
.bk-card[data-state="completed"] .bk-state { background: var(--ok-bg); color: var(--ok-ink); }

.bk-card[data-state="cancelled"] .bk-state,
.bk-card[data-state="noShow"] .bk-state { background: var(--bad-bg); color: var(--bad-ink); }

.bk-detail { margin: 0; font-size: 13.5px; color: var(--ink-2); }
.bk-title { margin: 10px 0 2px; font-size: 18px; }
.bk-who { margin: 0; font-weight: 600; }

.bk-facts {
  margin: 12px 0 0;
  display: grid;
  grid-template-columns: minmax(80px, max-content) 1fr;
  gap: 6px 14px;
}

.bk-facts dt { font-weight: 700; font-size: 13px; color: var(--ink-2); }
.bk-facts dd { margin: 0; font-size: 14.5px; overflow-wrap: anywhere; }
.bk-line { margin: 10px 0 0; font-size: 14px; line-height: 1.5; }
.bk-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.bk-panel { margin-top: 14px; padding: 14px; border-radius: var(--r-sm); background: var(--raised); }
.bk-panel-title { margin: 0 0 6px; font-size: 16px; }
.bk-status { margin: 10px 0 0; min-height: 1.4em; font-size: 14px; }
.bk-empty { color: var(--ink-2); }
.bk-back { margin-bottom: 14px; }

.bk-notice {
  margin: 0 0 14px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--info-bg);
  color: var(--info-ink);
  font-weight: 600;
}

/* ---- the practice page ---- */
.prac-note { color: var(--ink-2); font-size: 14px; max-width: 70ch; margin: 6px 0 14px; }
.prac-state { font-weight: 600; margin: 8px 0; }
.prac-warn { color: var(--error); font-weight: 600; font-size: 14px; }

.prac-card,
.prac-plan {
  max-width: 720px;
  margin: 16px 0;
  padding: clamp(18px, 2.2vw, 24px);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  background: var(--card);
}

.prac-card-title { margin: 0 0 8px; font-size: 18px; }

.prac-form,
.prac-offers,
.prac-week { max-width: 720px; }

.prac-offer-row,
.prac-day,
.prac-terms,
.prac-exceptions {
  max-width: 720px;
  margin: 0 0 14px;
  padding: 16px;
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  background: var(--card);
}

.prac-offer-row legend,
.prac-day legend,
.prac-terms legend,
.prac-exceptions legend { padding: 0 6px; font-weight: 700; }

.prac-inline { display: flex; flex-wrap: wrap; gap: 4px 18px; }
.prac-range { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 6px 14px; margin-bottom: 8px; }
.prac-range .spec-field { flex: 1 1 120px; margin-bottom: 0; }
.prac-exception { padding: 10px 0; border-top: 1px solid var(--hairline-2); }

.prac-select {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--control-line);
  border-radius: 10px;
  background: var(--field);
  color: var(--ink);
  font: inherit;
  font-size: 16px;  /* 16px stops iOS zooming the page on focus */
}

.prac-photo { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; margin-bottom: 18px; }
.prac-preview { margin-top: 18px; }
.prac-preview-day { margin: 4px 0; font-size: 14px; }

/* A field the server or the page refused: marked by outline AND by the
   sentence in the status line beside the Save button. */
.prac-wrap [aria-invalid="true"] { outline: 3px solid var(--error); outline-offset: 2px; }

/* ---- the invitation's landing (invite.html) ---- */
.inv-host { max-width: 720px; }
.inv-title { margin: 22px 0 10px; font-size: clamp(1.25rem, 2.4vw, 1.6rem); }
/* Focus is moved to each step's heading for screen readers; the ring is for
   keyboards, which reach the heading only by that move. */
.inv-title:focus:not(:focus-visible) { outline: none; }
.inv-line { margin: 0 0 12px; line-height: 1.55; max-width: 70ch; }
.inv-muted { color: var(--ink-2); font-size: 14px; }
.inv-org { margin: -4px 0 14px; color: var(--ink-2); font-weight: 600; }
.inv-sub { margin: 22px 0 6px; font-size: 17px; }
.inv-sub:focus:not(:focus-visible) { outline: none; }
.inv-list { margin: 0 0 12px; padding-left: 22px; line-height: 1.6; }
.inv-form { margin-top: 12px; max-width: 520px; }
.inv-ticks { margin: 10px 0 4px; }
/* A tick's whole line is its target, and it stays 44px high (the site's
   floor), wrapped labels included. */
.inv-ticks .spec-check { align-items: flex-start; min-height: 44px; margin: 4px 0 8px; }
.inv-ticks .spec-check input { margin-top: 3px; }
.inv-form [aria-invalid="true"] { outline: 3px solid var(--error); outline-offset: 2px; }
.inv-app { margin-top: 36px; padding-top: 12px; border-top: 1px solid var(--hairline-2); }

/* ---- the licence panel (invite.html, account.html) ---- */
.lic-line { margin: 0 0 10px; line-height: 1.55; max-width: 70ch; }
.lic-banner { font-weight: 600; }
.lic-live:empty { display: none; }
.lic-panel .pswitch { margin-top: 12px; }
.lic-panel .pswitch-b { min-height: 44px; }
.acct-licence { margin-top: 22px; }
/* Three tiers side by side inside the landing's narrower column. */
.inv-host .pcards { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.acct-licence-title { margin: 0 0 8px; font-size: 20px; }

/* ---- Sign-in methods (account.html, account-methods.js) ----
   One card, the account cards' own (--card, the --rule hairline, --r-lg),
   with a row per method divided by hairlines: the name, a state pill (the
   booking pills' green for Linked), the address the method gives, a line
   saying what the row is for, and its one action at the right; under 600
   px the action drops below the words. A confirmation or the add-password
   form opens inside the row on --raised, as a booking's cancel panel does.
   Google's and Apple's buttons are auth.css's (.auth-provider). */
.acct-methods-intro { margin: 8px 0 0; max-width: 62ch; color: var(--ink-2); }

.acct-methods {
  max-width: 820px;
  margin-top: 18px;
  padding: 6px clamp(20px, 2.4vw, 30px);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  background: var(--card);
}

.acct-methods-list { list-style: none; margin: 0; padding: 0; }
.acct-method { padding: 20px 0; }
.acct-method + .acct-method { border-top: 1px solid var(--hairline); }

.acct-method-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 28px;
}

.acct-method-text { flex: 1 1 280px; min-width: 0; }
.acct-method-name { margin: 0; font-size: 19px; }

.acct-method-state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin: 6px 0 0;
  font-size: 14px;
  color: var(--ink-2);
}

.acct-method-pill {
  padding: 2px 10px;
  border-radius: var(--r-pill);
  background: var(--raised);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
}

.acct-method-pill.is-on { background: var(--ok-bg); color: var(--ok-ink); }
.acct-method-email { overflow-wrap: anywhere; }

.acct-method-note,
.acct-method-hint {
  margin: 8px 0 0;
  max-width: 60ch;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-2);
}

.acct-method-hint { margin-top: 6px; font-size: 13px; }
.acct-method-actions { flex: 0 0 auto; }

/* The brands' buttons are full width in the sign-in dialog; in a row they
   take their own width, never narrower than the longest title needs. */
.acct-method-provider { width: auto; min-width: 260px; padding-inline: 20px; }

.acct-method-panel,
.acct-methods-reauth {
  margin-top: 14px;
  padding: 16px;
  border-radius: var(--r-sm);
  background: var(--raised);
}

.acct-method-panel[hidden],
.acct-methods-reauth[hidden],
.acct-methods-msg[hidden] { display: none; }

.acct-method-confirm { margin: 0 0 12px; max-width: 62ch; line-height: 1.45; }
.acct-method-row { display: flex; flex-wrap: wrap; gap: 10px; }
.acct-method-form { max-width: 420px; }
.acct-method-form .spec-field input[readonly] { color: var(--ink-2); }
.acct-method-form [aria-invalid="true"] { border-color: var(--error); }
.acct-methods-reauth-providers { display: grid; gap: 10px; max-width: 420px; margin: 0 0 16px; }
.acct-methods-reauth .auth-or { max-width: 420px; margin: 16px 0 12px; }
.acct-methods-reauth > .acct-method-row { margin-top: 4px; }

.acct-methods-msg {
  margin: 14px 0 4px;
  padding: 10px 14px;
  border-radius: var(--r-sm);
  font-size: 14.5px;
  line-height: 1.45;
}

.acct-methods-msg.is-ok { background: var(--ok-bg); color: var(--ok-ink); }
.acct-methods-msg.is-error { background: var(--bad-bg); color: var(--bad-ink); }
.acct-methods-msg.is-note { background: var(--raised); color: var(--ink); }

@media (max-width: 600px) {
  .acct-method-actions,
  .acct-method-provider { width: 100%; }
  .acct-method-actions .btn { width: 100%; }
  .acct-method-provider { min-width: 0; }
}

/* ------------------------------------------------------------------ news
   The News page (news.html) and the home page's "Latest news" card.

   news.html is a list of <article class="news-story">, newest first: an
   eyebrow, a dateline (.news-date), the headline, the story -- the order
   the home page's card uses too. The home page
   shows the newest one in brief (.news-latest), filled from that article at
   build time (tools/check_news.py). The iPhone Duo story's animation is
   assets/duo/, whose scene.css styles everything inside the stage; the duo-
   rules here are only the page's chrome around it: the poster shown without
   JavaScript, the Pause / Play button and the two stills shown under reduced
   motion (as the unpublished demo, demos/iphone-duo-welcome.html, drew
   them). Every class is prefixed news- or duo-, and none is defined in
   suite.css, auth.css or scene.css: the site already owns .device, .stage,
   .screen and more.
   -------------------------------------------------------------------- */

/* The page's own header sits close above the first story (outranking
   suite.css's .hero.band-white, which loads after this file). */
.hero.band-white.news-hero {
  padding-bottom: 0;
}

/* A link to a story (news.html#<id>, as the home page's card makes) puts
   the article's top at the top of the window, under the sticky bar (its
   bottom is about 75 px down). Where the story's own top padding is less
   than that, scroll-margin makes up the difference, so the dateline lands
   about 90 px down, clear of the bar; on wide screens it adds nothing. */
.news-story {
  padding-block: clamp(56px, 7vw, 104px);
  scroll-margin-top: max(0px, calc(90px - clamp(56px, 7vw, 104px)));
}

/* Two stories in a row: a hairline between them, inside the page's gutters
   (as suite.css draws .chapter-rule between two chapters). */
.news-story + .news-story {
  padding-top: 0;
}

.news-story + .news-story::before {
  content: '';
  display: block;
  width: calc(100% - 2 * var(--gut));
  max-width: calc(var(--page-wide) - 2 * var(--gut));
  height: 1px;
  margin: 0 auto clamp(56px, 7vw, 104px);
  background: var(--rule);
}

.news-story .intro,
.news-hero .intro {
  text-wrap: balance;
}

/* The dateline: small, in the secondary ink (5.0:1 on white, 8.2:1 on
   black; 4.6:1 and 6.5:1 on the card's --paper-2). */
.news-date {
  display: block;
  margin: 0 0 12px;
  font-size: 15px;
  line-height: 1.3;
  letter-spacing: 0.01em;
  color: var(--ink-2);
}

.duo-figure {
  max-width: 1080px;
  margin-top: clamp(28px, 4vw, 56px);
}

.duo-figure > figcaption {
  text-wrap: balance;
}

/* The moving picture is about 1.2 times as wide as it is tall: at its full
   1036 px it is 865 px tall, more than a laptop's window shows under the
   bar (1440 x 800, 1280 x 720, 1024 x 768), so the callout and the caption
   with its Pause button were never on screen together. Its width is capped
   by the window's height as well, so the whole stage, callout to caption,
   fits between the bar (its bottom about 74 px down) and the window's
   bottom edge, with about 16 px to spare at each end; never narrower than a
   phone's (316 px). The scene re-lays itself out at any width. The vh line
   is for browsers without svh. */
.duo-live {
  position: relative;
  max-width: max(316px, calc((100vh - 166px) * 1.27));
  max-width: max(316px, calc((100svh - 166px) * 1.27));
  margin-inline: auto;
}

.duo-host {
  position: relative;
  width: 100%;
}

/* The poster: the reveal as one picture, for a reader without JavaScript
   (and for the moment before the player starts). The player marks the
   figure .duo-ready, which hides it. A story with no animation shows its
   poster the same way, as .news-picture in a plain .big-stage figure. */
.news-picture,
.duo-fallback {
  display: block;
  width: 100%;
  max-width: 980px;
  height: auto;
  margin-inline: auto;
}

/* The poster keeps to the same height as the moving picture. */
.duo-fallback {
  max-width: min(980px, max(316px, calc((100vh - 166px) * 1.27)));
  max-width: min(980px, max(316px, calc((100svh - 166px) * 1.27)));
}

.duo-ready .duo-fallback {
  display: none;
}

/* While the player loads the scene (its fonts and pictures), web.js marks
   the figure .duo-loading and the poster stays up. The moving or still
   version is laid out at its full width, which the scene measures, but
   takes no room and is not seen: until 26 October 2026 the poster went as
   the script started and the story collapsed under a stage that had no
   height yet, with the Pause button floating over the caption. */
.duo-loading :is(.duo-live, .duo-stills) {
  height: 0;
  overflow: hidden;
  visibility: hidden;
}

/* The Pause / Play control: the site's 44 px round target, drawn like the
   bar's theme switch but on a filled disc so it reads as a control under
   the picture. Hidden until the player runs (it does nothing without it);
   web.js sets its top, on the caption's line. At the START of that line,
   which the scene keeps as clear as its end: at the end it shared the
   bottom-right corner with the floating Symbols switch, which covered half
   of it whenever it scrolled near the window's bottom edge (on a phone, the
   moment it took keyboard focus). */
.duo-controls {
  display: none;
  position: absolute;
  inset-inline-start: 0;
  top: 0;
}

.duo-ready .duo-controls {
  display: block;
}

.duo-toggle {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--paper-2);
  /* A hairline, so the disc reads as a button on either ground. */
  box-shadow: inset 0 0 0 1px var(--control-line);
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.duo-toggle:hover {
  background: var(--raised);
}

.duo-toggle:active {
  background: var(--wash-strong);
}

/* The site's ring, kept round (the global one squares it to 6 px). */
.duo-toggle:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 3px;
  border-radius: 50%;
}

.duo-toggle svg {
  display: block;
  width: 18px;
  height: 18px;
}

.duo-toggle[data-state='playing'] .duo-i-play,
.duo-toggle[data-state='paused'] .duo-i-pause {
  display: none;
}

/* prefers-reduced-motion: two still pictures, side by side. */
.duo-stills {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2.4vw, 32px);
}

.duo-stills[hidden] {
  display: none;
}

.duo-still {
  margin: 0;
}

.big-stage.duo-figure .duo-stills .duo-still figcaption {
  max-width: none;
  margin: 10px 0 0;
  font-size: 19px;
  font-weight: 600;
  color: var(--ink);
}

.duo-howto {
  max-width: 46ch;
  margin: 22px auto 0;
  font-size: 19px;
  line-height: 1.4;
  color: var(--ink-2);
}

.duo-howto strong {
  font-weight: 600;
  color: var(--ink);
}

.news-cta {
  justify-content: center;
  margin-top: 24px;
}

.news-notes {
  margin-top: 28px;
}

.news-notes p {
  margin: 0 0 6px;
}

/* An event's story (news.html #ataac-2026). Its picture is composed on the
   page rather than a still: the event's own logo as a mark on clear space,
   above the home page hero's three apps in their frames (suite.css
   .family, narrower here so the mark keeps its weight beside them). The
   logo file is 300 px square and is never shown wider than 150 CSS px: 144
   at most, sharp on a 2x screen, and 96 on a phone, sharp at 3x. It is an
   opaque bubble with a transparent surround and unmatted edges, so it sits
   on black and on white alike, with no tile behind it. */
/* Not a .big-stage: its .device.phone rule (auto side margins) would
   collapse .family's phones, whose width the grid gives them. */
.news-event-figure {
  margin: clamp(48px, 6vw, 80px) 0 0;
}

.news-event-mark {
  display: block;
  width: clamp(96px, 11vw, 144px);
  height: auto;
  margin: 0 auto;
}

/* Two classes, to outrank suite.css's .family (it loads after this file). */
.news-event-figure .family {
  max-width: 900px;
  margin-top: clamp(40px, 5vw, 64px);
}

/* The suite's three cards (suite.css .suite-cards): icon, name, line, link,
   with the line taking the slack, so the names sit level and the links
   stay at the bottom, as the product pages' two cards do. */
.news-event-apps a {
  grid-template-rows: auto auto 1fr auto;
}

.news-event-text {
  max-width: 46ch;
  margin: clamp(40px, 5vw, 64px) auto 0;
  font-size: 19px;
  line-height: 1.4;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* The home page's card: the newest story's date, headline and summary
   beside its still picture, on the --paper-2 surface the site's tiles use.
   It sits right under the hero, so the band has no top padding of its own. */
.news-latest-band {
  padding-block: 0 clamp(48px, 6vw, 88px);
}

.news-latest {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  align-items: center;
  gap: clamp(24px, 4vw, 56px);
  padding: clamp(28px, 4vw, 52px);
  border-radius: var(--r-lg);
  background: var(--paper-2);
  color: var(--ink);
  text-align: left;
}

/* On --paper-2 the accent is --blue-surface (5.2:1 in light, where --blue
   falls to 4.3:1), as on the tiles. */
.news-latest .eyebrow,
.news-latest .link-arrow {
  color: var(--blue-surface);
}

.news-latest .eyebrow {
  margin-bottom: 14px;
}

.news-latest .news-date {
  margin-bottom: 8px;
}

.news-latest-title {
  hyphens: auto;
  overflow-wrap: break-word;
}

.news-latest-summary {
  margin: 14px 0 0;
  max-width: 40ch;
  text-wrap: pretty;
  font-size: 19px;
  line-height: 1.4;
  color: var(--ink-2);
}

/* Under 834 px every .link-arrow is a full-width, centred row (the phone
   rule near .cta-row). From 761 to 833 px the card still has two columns
   and left-aligned words (an iPad held upright), so its link keeps to the
   left with them; under 761 px it is centred again, with the card. */
.news-latest .link-arrow {
  margin-top: 14px;
  justify-content: flex-start;
}

/* Only the card's own picture: the scene draws pictures of its own inside
   the card (scene.css sizes them), which a plain "img" here would squash. */
.news-latest-media > img,
.news-duo-poster {
  display: block;
  width: 100%;
  height: auto;
}

/* The card's animation (news-card.js starts it; index.html, "latest news"):
   the story's own scene in its card layout, which fills the box this CSS
   gives it. The box is the poster plus 56 px, the room the scene needs for
   the caption's line and the Pause / Play button under its phone, and it
   is the same box before the scene loads, while it loads, after, and if it
   fails to load (.duo-off), so nothing below the card moves whether the
   animation arrives or not (the card sits right under the hero, often in
   the window as the page opens). Until the scene is drawn the poster sits
   in the middle of that box, 28 px of the card's ground above and below,
   so the picture stays centred on the words beside it, and a poster that
   never gives way (a failed load, a blocked script) looks meant. The room
   is held only where the scene can come: with JavaScript (theme.js marks
   <html> with data-theme) and without reduced motion, where the card is
   the poster alone. The scene sizes its phone and its caption's lines into
   whatever box it is given. */
.news-duo {
  position: relative;
}

:root[data-theme] .news-duo:not(.duo-reduced) {
  padding-block: 28px;
}

@media (prefers-reduced-motion: reduce) {
  :root[data-theme] .news-duo:not(.duo-ready) {
    padding-block: 0;
  }
}

/* The scene is drawn: the poster keeps its room but is not seen (the
   stage's ground is clear, so it would show through). */
.news-duo.duo-ready .news-duo-poster {
  visibility: hidden;
}

.news-duo-live {
  position: absolute;
  inset: 0;
}

/* While it loads, the stage is laid out at its full size (the scene measures
   its box) but not seen; the poster is. */
.news-duo.duo-loading .news-duo-live {
  visibility: hidden;
}

.news-duo-host {
  position: relative;
  width: 100%;
  height: 100%;
}

/* A caption rises about 20 px into place as it fades in (scene.js cue()),
   and the card's band keeps only a few px under its last line: unclipped,
   the rise passes over the card's own padding instead of being cut off at
   the stage's edge (scene.css clips the stage, for the videos' frames). */
.news-duo .duo-stage {
  overflow: visible;
}

/* The Pause / Play button on the card's --paper-2: the fill of a field, so
   the disc stands off the card in both themes (#2c2c2e on #1d1d1f, white on
   #f5f5f7), its icon in --ink. It stays at the start of the caption's
   line (web.js sets its top): the card's padding keeps it and its focus
   ring off the card's edge, and the floating Symbols switch is at the far
   end of the window. */
.news-duo .duo-toggle {
  background-color: var(--field);
}

.news-duo .duo-toggle:hover {
  background-color: var(--field);
  background-image: linear-gradient(var(--wash), var(--wash));
}

.news-duo .duo-toggle:active {
  background-image: linear-gradient(var(--wash-strong), var(--wash-strong));
}

@media (max-width: 760px) {
  .duo-stills {
    grid-template-columns: 1fr;
  }

  /* One column: the picture first, then the words, centred as the site's
     tiles are. Keyboard focus keeps the source order, "Read the story"
     before the card's Pause / Play button (reading-flow: grid-order would
     follow the picture-first order, but Chrome 155 drops it once the
     scene has mounted, and Safari and Firefox do not have it). */
  .news-latest {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .news-latest-media {
    order: -1;
  }

  .news-latest-summary {
    margin-inline: auto;
  }

  .news-latest .link-arrow {
    justify-content: center;
  }
}

/* ----------------------------------------------------------------- print
   Paper is white whatever the screen is showing, and a browser drops
   background colours when it prints, so a dark page would print near-white
   text on white paper. Printing always uses the light theme: these are the
   :root[data-theme='light'] values above, repeated (keep the two in step). */
@media print {
  :root {
    color-scheme: light;
    --paper: #ffffff;
    --paper-2: #f5f5f7;
    --card: #ffffff;
    --raised: #f5f5f7;
    --field: #ffffff;
    --seg-on: #ffffff;
    --card-quiet: #f5f5f7;
    --rule: #d2d2d7;
    --rule-hover: #d2d2d7;
    --hairline: rgba(0, 0, 0, 0.11);
    --hairline-2: rgba(0, 0, 0, 0.08);
    --dashed: rgba(0, 0, 0, 0.24);
    --control-line: #c7c7cc;
    --float-line: rgba(0, 0, 0, 0.1);
    --cool-line: #e6eaf2;
    --cool-control: #d8dee9;
    --cool-frame: #d8dee9;
    --wash: rgba(0, 0, 0, 0.045);
    --wash-strong: rgba(0, 0, 0, 0.08);
    --track: rgba(0, 0, 0, 0.1);
    --rail: rgba(0, 0, 0, 0.16);
    --ink: #1d1d1f;
    --ink-2: #6e6e73;
    --ink-strong: #000000;
    --ink-hover: #3a3a3c;
    --cap-ink: #1d1d1f;
    --blue: #0071e3;
    --blue-hover: #0077ed;
    --blue-surface: #0066cc;
    --blue-wash: rgba(0, 113, 227, 0.08);
    --on-blue: #ffffff;
    --error: #b3261e;
    --danger: #d93025;
    --ok-bg: #e7f6ec;
    --ok-ink: #14532d;
    --bad-bg: #fdeaf0;
    --bad-ink: #6b1332;
    --info-bg: #e6efff;
    --info-ink: #14225c;
    --badge-bg: #eef1f6;
    --badge-ink: #46506a;
    --badge-super-bg: #e5edff;
    --badge-super-ink: #1b3faa;
    --nav-tray: rgba(236, 235, 232, 0.92);
    --nav-shadow:
      0 1px 2px rgba(0, 0, 0, 0.04),
      0 8px 24px rgba(0, 0, 0, 0.06);
    --nav-cap: linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.98),
      rgba(255, 255, 255, 0.82)
    );
    --nav-cap-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.9),
      inset 0 0 0 1px rgba(0, 0, 0, 0.11),
      0 1px 1px rgba(0, 0, 0, 0.05),
      0 4px 10px rgba(0, 0, 0, 0.07);
    --nav-cap-hover: linear-gradient(
      180deg,
      rgba(255, 255, 255, 1),
      rgba(255, 255, 255, 0.92)
    );
    --nav-cap-shadow-hover:
      inset 0 1px 0 rgba(255, 255, 255, 0.95),
      inset 0 0 0 1px rgba(0, 0, 0, 0.14),
      0 1px 2px rgba(0, 0, 0, 0.06),
      0 6px 14px rgba(0, 0, 0, 0.09);
    --nav-menu: #ffffff;
    --nav-menu-shadow:
      0 1px 2px rgba(0, 0, 0, 0.04),
      0 8px 24px rgba(0, 0, 0, 0.10);
    --nav-row: rgba(0, 0, 0, 0.07);
    --nav-cur: rgba(0, 0, 0, 0.05);
    --nav-cur-ring: rgba(0, 0, 0, 0.11);
    --shadow-lift: 0 18px 36px -22px rgba(0, 0, 0, 0.45);
    --shadow-hi: 0 20px 44px -26px rgba(45, 108, 223, 0.55);
    --shadow-seg: 0 1px 3px rgba(0, 0, 0, 0.12);
    --shadow-float: 0 6px 20px rgba(0, 0, 0, 0.14), 0 1px 3px rgba(0, 0, 0, 0.08);
    --shadow-float-hover: 0 10px 26px rgba(0, 0, 0, 0.18), 0 1px 3px rgba(0, 0, 0, 0.08);
  }
}
