/* ════════════════════════════════════════════════════════════════════
   Ullman Eye Consultants — low vision controls
   A FIRST-PARTY control, deliberately not a third-party overlay. The
   overlay products (accessiBe and friends) fight the magnifiers, browser
   zoom and OS high-contrast modes that low vision patients already run -
   WebAIM's Low Vision Survey found 47% use a magnifier, 47% browser zoom,
   30% an OS high contrast mode. Everything here only sets CSS on this
   site and stops there, so those tools keep working on top of it.

   The same survey is why the controls exist at all: 78% of low vision
   respondents wished more pages offered text sizing, and 93% said default
   web text is too small unaided.

   State lives on <html> as data-a11y-text (0-3) and data-a11y-contrast
   (off | dark | light), set by js/accessibility.js and remembered in
   localStorage so it carries across pages.
   ════════════════════════════════════════════════════════════════════ */

/* ── 1. Text size ───────────────────────────────────────────────────
   The site's CSS is Webflow-generated and almost entirely in px, so
   rescaling the root font-size would move almost nothing. zoom rescales
   the used values instead, and - unlike transform: scale() - it reflows,
   so lines re-wrap and no horizontal scrollbar appears. Horizontal
   scrolling is the one thing WebAIM singles out as worst for low vision. */
html[data-a11y-text="1"] body { zoom: 1.15; }
html[data-a11y-text="2"] body { zoom: 1.3; }
html[data-a11y-text="3"] body { zoom: 1.5; }

/* ── High contrast, dark ───────────────────────────────────
   White on black is 21:1 and amber on black 16:1, both well past the 7:1
   AAA threshold. The W3C's low vision guidance is explicit that this is the
   mode some patients need and the bright one below is what others need.

   About ":not(#uec)" on nearly every selector below: the site's own CSS
   sets some backgrounds with !important AND a higher specificity than a
   plain "html[attr] *" - .header and .hero-heading-center.phone.tablet
   both do. Between two !important author rules, specificity decides, so
   those hero rules won and the banner kept its light background while the
   text on it was forced light: invisible. :not(#uec) contributes an ID's
   worth of specificity (no element has that id, so it still matches
   everything), which lifts these above any class-based rule on the site.
   ─────────────────────────────────────────────────────────────────── */
html[data-a11y-contrast="dark"] { background-color: #000 !important; }

html[data-a11y-contrast="dark"] *:not(#uec) {
  /* Buttons on this site transition their background. Switching mode starts
     that transition from the brand colour, and the audit caught CTAs still
     sitting at #00437f with contrast-mode text on top - 1.4:1. Nothing here
     should animate anyway: the switch should be instant. */
  transition: none !important;
  animation-duration: 0s !important;
  background-color: transparent !important;
  background-image: none !important;
  color: #fff !important;
  border-color: #fff !important;
  box-shadow: none !important;
  text-shadow: none !important;
}

/* Pseudo-elements take the colours but never a forced background: painting
   an opaque box behind every ::before/::after covers real content. */
html[data-a11y-contrast="dark"] *:not(#uec)::before,
html[data-a11y-contrast="dark"] *:not(#uec)::after {
  background-image: none !important;
  color: #fff !important;
  border-color: #fff !important;
  box-shadow: none !important;
  text-shadow: none !important;
}

/* ── The lens banners ──
   These lay copy over a full-bleed product shot, held readable by
   .lens-media__cap: an absolutely-positioned gradient scrim. Stripping
   background images deleted that scrim and dropped white headings onto a
   white pair of glasses. In a contrast mode the artwork goes entirely -
   the copy is what has to be readable, and a photograph cannot be forced
   to a safe colour the way text can.

   The artwork was also what gave each band its height, with the caption
   absolutely positioned on top of it. Remove one and the other has to
   stop floating, or the bands collapse into each other. */
html[data-a11y-contrast="dark"] .lens-media__vid:not(#uec),
html[data-a11y-contrast="dark"] .lens-media__shot:not(#uec) {
  display: none !important;
}

html[data-a11y-contrast="dark"] .lens-media__cap:not(#uec) {
  position: static !important;
  inset: auto !important;
  padding: 26px 0 30px !important;
}

html[data-a11y-contrast="dark"] .lens-media__copy:not(#uec) {
  max-width: none !important;
}

/* The "Watch on YouTube" chip and the play button carry their own dark
   plate because they sit on a video thumbnail, which does survive: it is a
   real link to a video, not decoration. */
html[data-a11y-contrast="dark"] .info-watch:not(#uec),
html[data-a11y-contrast="dark"] .info-play:not(#uec) {
  background-color: #000 !important;
}

/* The exceptions - page content scrolls underneath these, so they have to
   stay opaque or the text collides. */
html[data-a11y-contrast="dark"] .navigation-3:not(#uec),
html[data-a11y-contrast="dark"] .navigation:not(#uec),
html[data-a11y-contrast="dark"] .navigation-container:not(#uec),
html[data-a11y-contrast="dark"] .w-nav-menu:not(#uec),
html[data-a11y-contrast="dark"] .w-dropdown-list:not(#uec) {
  background-color: #000 !important;
}

html[data-a11y-contrast="dark"] a:not(#uec),
html[data-a11y-contrast="dark"] a *:not(#uec) { color: #ffe14d !important; text-decoration: underline !important; }
html[data-a11y-contrast="dark"] a:hover:not(#uec),
html[data-a11y-contrast="dark"] a:focus-visible:not(#uec) { color: #fff !important; }

/* outline, not border: a border enlarges the box and shunted the header. */
html[data-a11y-contrast="dark"] button *:not(#uec),
html[data-a11y-contrast="dark"] .nf__cta *:not(#uec),
html[data-a11y-contrast="dark"] .lens-media__cta *:not(#uec),
html[data-a11y-contrast="dark"] .w-button *:not(#uec) { text-decoration: none !important; }

html[data-a11y-contrast="dark"] button:not(#uec),
html[data-a11y-contrast="dark"] .nf__cta:not(#uec),
html[data-a11y-contrast="dark"] .lens-media__cta:not(#uec),
html[data-a11y-contrast="dark"] .w-button:not(#uec),
html[data-a11y-contrast="dark"] input[type="submit"]:not(#uec) {
  background-color: #000 !important;
  color: #ffe14d !important;
  outline: 2px solid #ffe14d !important;
  outline-offset: -2px !important;
  text-decoration: none !important;
}

/* The practice logo is dark blue on transparent and would vanish on black.
   The same is true of the university and board logos in the doctors' bios -
   .image-27/29/30/31 are the UF, Georgetown, Bascom Palmer, Baylor, UAB,
   Devers, Wills, Washington University, ABO and AOA marks. They are artwork
   drawn for a white page, so on black they need the white page back. */
html[data-a11y-contrast="dark"] img[src*="Ullman-Eye-Logo"]:not(#uec) {
  background: #fff !important;
  padding: 6px !important;
  border-radius: 4px !important;
}

html[data-a11y-contrast="dark"] .image-27:not(#uec),
html[data-a11y-contrast="dark"] .image-29:not(#uec),
html[data-a11y-contrast="dark"] .image-30:not(#uec),
html[data-a11y-contrast="dark"] .image-31:not(#uec) {
  background: #fff !important;
  padding: 8px !important;
  border-radius: 6px !important;
  box-sizing: border-box !important;
}

/* ── High contrast, light ───────────────────────────────────
   Black on white, also 21:1, for patients who need brightness rather than
   relief from it.

   About ":not(#uec)" on nearly every selector below: the site's own CSS
   sets some backgrounds with !important AND a higher specificity than a
   plain "html[attr] *" - .header and .hero-heading-center.phone.tablet
   both do. Between two !important author rules, specificity decides, so
   those hero rules won and the banner kept its light background while the
   text on it was forced light: invisible. :not(#uec) contributes an ID's
   worth of specificity (no element has that id, so it still matches
   everything), which lifts these above any class-based rule on the site.
   ─────────────────────────────────────────────────────────────────── */
html[data-a11y-contrast="light"] { background-color: #fff !important; }

html[data-a11y-contrast="light"] *:not(#uec) {
  /* Buttons on this site transition their background. Switching mode starts
     that transition from the brand colour, and the audit caught CTAs still
     sitting at #00437f with contrast-mode text on top - 1.4:1. Nothing here
     should animate anyway: the switch should be instant. */
  transition: none !important;
  animation-duration: 0s !important;
  background-color: transparent !important;
  background-image: none !important;
  color: #000 !important;
  border-color: #000 !important;
  box-shadow: none !important;
  text-shadow: none !important;
}

/* Pseudo-elements take the colours but never a forced background: painting
   an opaque box behind every ::before/::after covers real content. */
html[data-a11y-contrast="light"] *:not(#uec)::before,
html[data-a11y-contrast="light"] *:not(#uec)::after {
  background-image: none !important;
  color: #000 !important;
  border-color: #000 !important;
  box-shadow: none !important;
  text-shadow: none !important;
}

/* ── The lens banners ──
   These lay copy over a full-bleed product shot, held readable by
   .lens-media__cap: an absolutely-positioned gradient scrim. Stripping
   background images deleted that scrim and dropped white headings onto a
   white pair of glasses. In a contrast mode the artwork goes entirely -
   the copy is what has to be readable, and a photograph cannot be forced
   to a safe colour the way text can.

   The artwork was also what gave each band its height, with the caption
   absolutely positioned on top of it. Remove one and the other has to
   stop floating, or the bands collapse into each other. */
html[data-a11y-contrast="light"] .lens-media__vid:not(#uec),
html[data-a11y-contrast="light"] .lens-media__shot:not(#uec) {
  display: none !important;
}

html[data-a11y-contrast="light"] .lens-media__cap:not(#uec) {
  position: static !important;
  inset: auto !important;
  padding: 26px 0 30px !important;
}

html[data-a11y-contrast="light"] .lens-media__copy:not(#uec) {
  max-width: none !important;
}

/* The "Watch on YouTube" chip and the play button carry their own dark
   plate because they sit on a video thumbnail, which does survive: it is a
   real link to a video, not decoration. */
html[data-a11y-contrast="light"] .info-watch:not(#uec),
html[data-a11y-contrast="light"] .info-play:not(#uec) {
  background-color: #fff !important;
}

/* The exceptions - page content scrolls underneath these, so they have to
   stay opaque or the text collides. */
html[data-a11y-contrast="light"] .navigation-3:not(#uec),
html[data-a11y-contrast="light"] .navigation:not(#uec),
html[data-a11y-contrast="light"] .navigation-container:not(#uec),
html[data-a11y-contrast="light"] .w-nav-menu:not(#uec),
html[data-a11y-contrast="light"] .w-dropdown-list:not(#uec) {
  background-color: #fff !important;
}

html[data-a11y-contrast="light"] a:not(#uec),
html[data-a11y-contrast="light"] a *:not(#uec) { color: #00296b !important; text-decoration: underline !important; }
html[data-a11y-contrast="light"] a:hover:not(#uec),
html[data-a11y-contrast="light"] a:focus-visible:not(#uec) { color: #000 !important; }

/* outline, not border: a border enlarges the box and shunted the header. */
html[data-a11y-contrast="light"] button *:not(#uec),
html[data-a11y-contrast="light"] .nf__cta *:not(#uec),
html[data-a11y-contrast="light"] .lens-media__cta *:not(#uec),
html[data-a11y-contrast="light"] .w-button *:not(#uec) { text-decoration: none !important; }

html[data-a11y-contrast="light"] button:not(#uec),
html[data-a11y-contrast="light"] .nf__cta:not(#uec),
html[data-a11y-contrast="light"] .lens-media__cta:not(#uec),
html[data-a11y-contrast="light"] .w-button:not(#uec),
html[data-a11y-contrast="light"] input[type="submit"]:not(#uec) {
  background-color: #fff !important;
  color: #000 !important;
  outline: 2px solid #000 !important;
  outline-offset: -2px !important;
  text-decoration: none !important;
}

/* Mirror of the dark-mode problem: white social glyphs on white. */
html[data-a11y-contrast="light"] .image-26:not(#uec) {
  background: #000 !important;
  padding: 4px !important;
  border-radius: 4px !important;
}

/* ── 4. Effects that work against the reader ────────────────────────
   The 404 numeral breathes in and out of focus as a joke about being an
   eye practice. It is precisely the wrong thing to show someone who
   turned these controls on, so any of them switches it off. */
html[data-a11y-contrast="dark"] .nf__number,
html[data-a11y-contrast="light"] .nf__number,
html[data-a11y-text="1"] .nf__number,
html[data-a11y-text="2"] .nf__number,
html[data-a11y-text="3"] .nf__number {
  animation: none !important;
  filter: none !important;
}

/* ════════════════════════════════════════════════════════════════════
   The control itself
   ════════════════════════════════════════════════════════════════════ */

.a11y-fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 2px solid #fff;
  border-radius: 50%;
  background: #00437f;
  color: #fff;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 31, 61, .34);
  transition: background-color .18s ease, transform .18s ease;
}

.a11y-fab:hover { background: #25508b; transform: translateY(-2px); }
.a11y-fab:focus-visible { outline: 3px solid #ffb300; outline-offset: 3px; }
.a11y-fab svg { width: 30px; height: 30px; display: block; }

.a11y-panel {
  position: fixed;
  right: 20px;
  bottom: 88px;
  z-index: 9001;
  width: 290px;
  max-width: calc(100vw - 40px);
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  padding: 18px;
  box-sizing: border-box;
  border: 2px solid #00437f;
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 10px 40px rgba(0, 31, 61, .28);
  font-family: "Libre Franklin", Helvetica, Arial, sans-serif;
  color: #283338;
  text-align: left;
}

.a11y-panel[hidden] { display: none; }

.a11y-panel__title {
  margin: 0 0 4px;
  font-size: 17px;
  font-weight: 700;
  color: #283338;
}

.a11y-panel__intro {
  margin: 0 0 14px;
  font-size: 13px;
  line-height: 1.5;
  color: #4a5763;
}

.a11y-group { margin-bottom: 15px; }

.a11y-group__label {
  display: block;
  margin-bottom: 7px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: #4a5763;
}

.a11y-row { display: flex; flex-wrap: wrap; gap: 7px; }

.a11y-opt {
  flex: 1 1 auto;
  min-width: 44px;
  min-height: 44px;
  padding: 8px 10px;
  border: 2px solid #c9d7e8;
  border-radius: 9px;
  background: #fff;
  color: #00437f;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}

.a11y-opt:hover { border-color: #00437f; background: #f2f7fd; }
.a11y-opt:focus-visible { outline: 3px solid #ffb300; outline-offset: 2px; }
.a11y-opt[aria-pressed="true"] { background: #00437f; border-color: #00437f; color: #fff; }

.a11y-opt--a1 { font-size: 14px; }
.a11y-opt--a2 { font-size: 17px; }
.a11y-opt--a3 { font-size: 20px; }
.a11y-opt--a4 { font-size: 23px; }

.a11y-reset {
  width: 100%;
  min-height: 44px;
  margin-top: 2px;
  border: 2px solid #00437f;
  border-radius: 9px;
  background: #fff;
  color: #00437f;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.a11y-reset:hover { background: #00437f; color: #fff; }
.a11y-reset:focus-visible { outline: 3px solid #ffb300; outline-offset: 2px; }

.a11y-note {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: #6b7783;
}

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

/* The panel is part of the answer, so it must stay legible in the modes
   the blanket rules above would otherwise repaint it with. These
   selectors outrank those by one class. */
html[data-a11y-contrast="dark"] .a11y-panel:not(#uec),
html[data-a11y-contrast="dark"] .a11y-panel:not(#uec) * { background-color: #000 !important; color: #fff !important; border-color: #fff !important; }
html[data-a11y-contrast="dark"] .a11y-fab:not(#uec) { background-color: #000 !important; color: #ffe14d !important; border-color: #ffe14d !important; }
html[data-a11y-contrast="dark"] .a11y-opt[aria-pressed="true"]:not(#uec),
html[data-a11y-contrast="dark"] .a11y-reset:hover:not(#uec) { background-color: #ffe14d !important; color: #000 !important; border-color: #ffe14d !important; }

html[data-a11y-contrast="light"] .a11y-panel:not(#uec),
html[data-a11y-contrast="light"] .a11y-panel:not(#uec) * { background-color: #fff !important; color: #000 !important; border-color: #000 !important; }
html[data-a11y-contrast="light"] .a11y-fab:not(#uec) { background-color: #fff !important; color: #000 !important; border-color: #000 !important; }
html[data-a11y-contrast="light"] .a11y-opt[aria-pressed="true"]:not(#uec),
html[data-a11y-contrast="light"] .a11y-reset:hover:not(#uec) { background-color: #000 !important; color: #fff !important; border-color: #000 !important; }

/* Windows High Contrast / forced-colors: hand the whole thing over to the
   system palette rather than fighting it - that is the overlay mistake. */

/* ════════════════════════════════════════════════════════════════════
   Windows High Contrast / Contrast Themes (forced-colors)
   Separate from the buttons above, and not something a patient turns on
   here - the operating system does it, and the browser then overrides
   colours across the whole page whether this site cooperates or not.

   Two things break under it, both confirmed by emulating the mode:

   1. The OS strips gradient backgrounds. .lens-media__cap IS a gradient
      scrim - it is the only thing making the banner copy readable over a
      product photograph. Windows removes it and leaves white text on a
      white pair of glasses. Same failure the site's own dark mode had,
      arriving by a different route, so it gets the same fix.
   2. Images are passed through untouched, by design - the browser cannot
      know which are photographs. A dark blue logo on a black system
      background therefore disappears. forced-color-adjust: none opts
      those few images out so they can keep a white plate.
   ════════════════════════════════════════════════════════════════════ */
@media (forced-colors: active) {
  .lens-media__vid,
  .lens-media__shot { display: none !important; }

  .lens-media__cap {
    position: static !important;
    inset: auto !important;
    padding: 26px 0 30px !important;
  }

  .lens-media__copy { max-width: none !important; }

  img[src*="Ullman-Eye-Logo"],
  .image-27, .image-29, .image-30, .image-31 {
    forced-color-adjust: none !important;
    background: #fff !important;
    padding: 6px !important;
    border-radius: 4px !important;
  }
}

@media (forced-colors: active) {
  .a11y-fab, .a11y-panel, .a11y-opt, .a11y-reset {
    forced-color-adjust: auto;
    border: 2px solid ButtonBorder;
    background: ButtonFace;
    color: ButtonText;
  }
  .a11y-opt[aria-pressed="true"] { background: Highlight; color: HighlightText; }
}

@media (prefers-reduced-motion: reduce) {
  .a11y-fab { transition: none; }
  .a11y-fab:hover { transform: none; }
}

@media print {
  .a11y-fab, .a11y-panel { display: none !important; }
}
