/* KK UI GOVERNOR - MODERNIZATION LAYER
   Generated by a single governed run. Every rule below was applied to the
   running application, measured across the device matrix, and kept only
   because the measurement came back equal or better on every scenario.
   Delete this file and its import to remove the entire layer. */

/* ---- design.tokens (design) - A token scale built from the values this product already uses
   Sizes, radii and spacing drift as a product grows until a dozen near-identical values are in use and none of them mean anything. Clustering the measured values into a scale keeps every decision this product has already made and removes only the accidents between them. The scale is this product's, not a house scale. */
/* Derived from this product's own rendered values. Every number below is
   one the product already uses; only the names are new. Nearby values were
   collapsed onto their most-used member, so drift is removed without any
   decision being replaced. */
:where(:root) {
  --kk-text-1: 13.5px;
  --kk-radius-1: 5.4px;
  --kk-radius-2: 18px;
  --kk-radius-3: 50%;
  --kk-radius-4: 899.1px;
  --kk-space-1: 9px;
  --kk-shadow-1: rgba(255, 255, 255, 0.95) 0px 0.9px 0px 0px inset, rgba(31, 35, 39, 0.043) 0px 3.6px 9.9px 0px;
  --kk-shadow-2: rgba(255, 255, 255, 0.03) 0px 0.9px 0px 0px inset, rgba(0, 0, 0, 0.11) 0px 4.5px 11.7px 0px;
  --kk-shadow-3: rgba(255, 255, 255, 0.96) 0px 0.9px 0px 0px inset, rgba(31, 35, 39, 0.075) 0px 5.4px 14.4px 0px, rgba(31, 35, 39, 0.04) 0px 14.4px 30.6px 0px;
}

/* ---- design.type-rhythm (design) - Body text gets a readable measure and a settled line height
   Lines longer than about 80 characters lose the reader on the return sweep, and body text set tighter than 1.5 makes the same problem worse. The sizes stay exactly as they are; only the rhythm around them is settled. */
:where(p, li, dd, blockquote) {
  line-height: 1.5;
}
:where(h1, h2, h3, h4, h5, h6) {
  line-height: 1.3;
  text-wrap: balance;
}
/* A paragraph that is the only thing in its column gets a measure. */
:where(article, .prose, [class*="prose"]) :where(p) {
  max-inline-size: 80ch;
}

/* ---- design.state-surface (design) - Disabled and busy controls look and behave like what they are
   A control that is disabled but still takes the pointer, or busy but still looks idle, is the most common reason a user clicks the same button four times. The appearance is expressed as reduced opacity over whatever the control already is, so the product's own colours are what fade. */
:where(button, [role="button"], input, select, textarea):disabled,
:where([aria-disabled="true"]) {
  cursor: not-allowed;
  opacity: 0.55;
}
:where(button, [role="button"]):disabled,
:where([aria-disabled="true"]) {
  pointer-events: none;
}
:where([aria-busy="true"]) {
  cursor: progress;
}

/* ---- responsive.core (responsive) - Nothing can push the page wider than the screen
   Horizontal page scroll is never a design decision; it is always something overflowing. Media, embedded frames, form controls and long unbroken strings are the four things that cause it, and each is capped at its own container here. */
:where(html) { text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
:where(img, video, canvas, svg, picture) { max-inline-size: 100%; block-size: auto; }
:where(iframe, embed, object) { max-inline-size: 100%; }
:where(iframe, embed, object, img, video, canvas, input, select, textarea,
       button, fieldset, table) { box-sizing: border-box; }
:where(input, select, textarea, button, fieldset) { max-inline-size: 100%; min-inline-size: 0; }
:where(pre) { max-inline-size: 100%; overflow-x: auto; overscroll-behavior-x: contain; }
:where(code):not(pre code) { overflow-wrap: break-word; }
:where([hidden]):not([hidden="until-found"]) { display: none !important; }

/* ---- responsive.table-scroll (responsive) - A wide table scrolls inside itself instead of clipping
   A table with more columns than a phone can show has to go somewhere. Scrolling it within its own box keeps every cell reachable, where releasing the page width alone just moves the clipping inside the table. */
@media (max-width: 900px) {
  :where(table) {
    display: block;
    max-inline-size: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }
}

/* ---- responsive.scroller-keyboard (responsive) - Anything that scrolls can be scrolled from the keyboard
   A scroll container that nothing can focus is unreachable without a pointer. Giving it a tab stop is what axe asks for, and it costs nothing for anyone who does not need it because a container with no overflow is not focusable in the first place. */
:where([style*="overflow"], pre, table):focus-visible {
  outline: 2px solid currentColor;
  outline-offset: -2px;
}

/* ---- responsive.row-wrap (responsive) - Rows of boxes wrap on small screens instead of clipping
   A row of comparable boxes laid out side by side with wrapping switched off has nowhere to put its last child on a narrow screen, so it cuts it off. Below 900px they are allowed to wrap. A page shell - a narrow rail beside a wide main region - is left alone, because its children are not peers and wrapping it restructures the page. */
@media (max-width: 900px) {
  header.topbar { flex-wrap: wrap; }
  section.op-title { flex-wrap: wrap; }
  a.decision-row { flex-wrap: wrap; }
  div.op-panel-head { flex-wrap: wrap; }
  div.topbar-right { flex-wrap: wrap; }
}

/* ---- responsive.dynamic-viewport (responsive) - Full-height layouts survive the mobile address bar
   100vh is the viewport with the browser chrome retracted, so a layout built on it is cut off by the address bar on first paint and jumps when it hides. The dynamic viewport units track the space that is actually available. */
/* ------------------------------------------------------------------ shell */ #app { block-size: 100dvh; min-block-size: 100dvh; }
#app { block-size: 100dvh; min-block-size: 100dvh; }

/* ---- responsive.safe-areas (responsive) - Fixed furniture keeps clear of the home indicator and the cutout
   A bar pinned to an edge sits under the display cutout or the 21pt home indicator on the devices that have them, which is where its controls become unhittable. The safe-area insets are zero on every device without them, so the padding costs nothing elsewhere. */
.tabbar {
  padding-inline: max(env(safe-area-inset-left), 0px) max(env(safe-area-inset-right), 0px);
  padding-block-end: max(env(safe-area-inset-bottom), 0px);
}
.pcc-drawer {
  padding-inline: max(env(safe-area-inset-left), 0px) max(env(safe-area-inset-right), 0px);
  padding-block-end: max(env(safe-area-inset-bottom), 0px);
}

/* ---- responsive.ultrawide (responsive) - Text stops stretching on very wide displays
   Prose set the full width of a 2560px display runs well past the 80-character measure the eye can track, so the reader loses their place returning to the left edge. Only the measure is capped; the layout around it is untouched. */
@media (min-width: 1900px) {
  :where(p, li, dd, blockquote):not([class*="grid"] *) { max-inline-size: 80ch; }
}

/* ---- responsive.zoom-reflow (responsive) - The page still works at 200% text and 320px wide
   WCAG 1.4.10 Reflow asks that content survive a 320 CSS pixel viewport and 1.4.4 asks that it survive 200% text, both without scrolling in two directions at once. Fixed heights on text containers are the usual thing that breaks it. */
@media (max-width: 360px) {
  :where(body) { overflow-x: hidden; }
  :where(h1, h2, h3) { overflow-wrap: anywhere; }
}
/* A box sized to today's text cannot hold tomorrow's. */
:where(p, li, dd, label, .card, [class*="card"]) { block-size: auto; }

/* ---- interaction.states (interaction) - Every control answers hover, press and focus
   A control that looks identical before and during a press gives no evidence the press registered, which is what produces double submissions. The feedback is an inset tint over whatever colour the control already has, so it reads correctly on a light or a dark surface without knowing which one it is on. */
@media (hover: hover) {
  :where(a[href], button, [role="button"], summary):hover:not(:disabled) {
    box-shadow: inset 0 0 0 100vmax rgb(0 0 0 / 0.06);
  }
}
@media (hover: hover) and (prefers-color-scheme: dark) {
  :where(a[href], button, [role="button"], summary):hover:not(:disabled) {
    box-shadow: inset 0 0 0 100vmax rgb(255 255 255 / 0.09);
  }
}
:where(a[href], button, [role="button"], summary):active:not(:disabled) {
  box-shadow: inset 0 0 0 100vmax rgb(0 0 0 / 0.12);
}
@media (hover: none) {
  :where(a[href], button, [role="button"]):active { opacity: 0.7; }
}
:where(a[href], button, [role="button"], summary, input, select, textarea) {
  touch-action: manipulation;
}

/* ---- interaction.motion-system (interaction) - Transitions get a duration and a curve that suit their direction
   Material publishes paired curves because entering and leaving are not the same motion: something arriving should decelerate into place, something leaving should accelerate away. Using one curve for both is the most common reason motion feels wrong rather than slow. These values apply only where no transition was specified. */
:where(:root) {
  --kk-motion-micro: 100ms;
  --kk-motion-state: 200ms;
  --kk-motion-enter: 300ms;
  --kk-motion-exit: 200ms;
  --kk-ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --kk-ease-enter: cubic-bezier(0.05, 0.7, 0.1, 1);
  --kk-ease-exit: cubic-bezier(0.3, 0, 0.8, 0.15);
}
:where(a[href], button, [role="button"], input, select, textarea, summary) {
  transition-duration: var(--kk-motion-state);
  transition-timing-function: var(--kk-ease-standard);
}

/* ---- interaction.reduced-motion (interaction) - Reduced motion removes movement without removing feedback
   prefers-reduced-motion is a request to avoid vestibular triggers - translation, scale, parallax - not a request for a dead interface. Durations collapse and movement stops, while colour and opacity still carry the state change, so nothing becomes harder to understand. */
@media (prefers-reduced-motion: reduce) {
  :where(*, *::before, *::after) {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  :where(*) { view-transition-name: none !important; }
}

/* ---- interaction.scroll-anchoring (interaction) - A swipe inside a scroller does not drag the page with it
   Scroll chaining is why a horizontal swipe through a table on a phone ends up navigating back or bouncing the whole page. Containing the overscroll keeps the gesture where the user aimed it. */
:where(pre, table, [class*="scroll"], [style*="overflow"]) {
  overscroll-behavior: contain;
}
:where(html) { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { :where(html) { scroll-behavior: auto; } }

/* ---- a11y.focus-visible (accessibility) - Keyboard focus is always visible, and visible against anything
   An outline removed for looking untidy on click removes it for the keyboard too. :focus-visible restores it only where a keyboard is driving. The ring is drawn in currentColor with a contrasting halo, so it is visible on whatever surface it lands on without the rule knowing what colour that surface is. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  border-radius: inherit;
}
@media (forced-colors: active) {
  :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline-color: Highlight !important;
  }
}

/* ---- a11y.focus-not-obscured (accessibility) - Sticky furniture cannot hide the control that just took focus
   WCAG 2.2 adds 2.4.11 Focus Not Obscured at Level AA: tabbing to a control that then scrolls under a sticky header is a failure, not an annoyance. Scroll margin the height of the sticky furniture keeps the focused control below it. */
:where(a, button, input, select, textarea, summary, [tabindex]) {
  scroll-margin-block: 6rem 2rem;
}

/* ---- a11y.target-size (accessibility) - Touch targets reach the size a finger needs
   WCAG 2.5.8 sets 24x24 CSS pixels as the conformance floor at Level AA. Only the floor is applied. An earlier version of this rule also grew the hit area with an absolutely positioned pseudo-element so that a coarse pointer got the 44pt Apple and 48dp Material both ask for; measured against a dense list that added 206 clipped elements on one view, because a child larger than its parent is overflow whatever it is for. The platform size is worth having and is not worth that, so it is left to the product. */
:where(a[href], button, [role="button"], input[type="checkbox"], input[type="radio"], summary) {
  min-block-size: 24px;
  min-inline-size: min(24px, 100%);
}

/* ---- a11y.contrast (accessibility) - Text that failed contrast is corrected to the threshold, and no further
   WCAG 1.4.3 asks 4.5:1 for body text and 3:1 for large text. Each failing colour is walked toward the far end of the range along its own hue until it just reaches the threshold, and checked against every background it appears on. A colour saturated enough to be carrying brand meaning is reported instead of changed - a brand is not the Governor's to correct. */
/* Muted text colours raised to AA against every background they were measured on. */
small#rail-me-role { color: #6f7c8b; }
@media (forced-colors: active) {
  small#rail-me-role { color: CanvasText; }
}

/* ---- a11y.forced-colors (accessibility) - High contrast mode gets to win
   Someone using a forced-colors mode has chosen their palette deliberately, usually because they cannot read the default one. Backgrounds painted with images or gradients survive that mode and cover their own text. Yielding to the system colours is the whole contract. */
@media (forced-colors: active) {
  :where(*) { forced-color-adjust: auto; }
  :where([class*="gradient"], [style*="gradient"]) { background-image: none; }
  :where(button, [role="button"], input, select, textarea) {
    border: 1px solid ButtonBorder;
  }
}

/* ---- a11y.motion-safety (accessibility) - Nothing moves by itself for longer than a person can tolerate
   WCAG 2.2.2 asks for a way to pause anything that moves for more than 5 seconds and starts on its own. Where no control exists, the safest correction is to stop the animation for anyone who has asked for reduced motion, which is the population the criterion protects. */
@media (prefers-reduced-motion: reduce) {
  :where([class*="marquee"], [class*="carousel"], [class*="ticker"], [class*="autoplay"]) {
    animation-play-state: paused !important;
  }
}

/* ---- platform.touch-ergonomics (interaction) - Touch gets touch behaviour and pointers keep pointer behaviour
   Hover styles on a touch device stick after a tap because there is nothing to move the pointer away, which leaves controls looking permanently pressed. Splitting the two by capability rather than by screen width is what stops a laptop with a touchscreen getting the wrong one. */
@media (hover: none) and (pointer: coarse) {
  :where(a[href], button, [role="button"]) { -webkit-tap-highlight-color: transparent; }
  :where([class*="tooltip"]) { display: none; }
}

/* ---- platform.scrollbar-stability (design) - The page does not jump sideways when a scrollbar appears
   On Windows and Linux the classic scrollbar takes width from the page, so content shifts horizontally the moment a route becomes long enough to scroll. The gutter is reserved only from 640px up: below that the reserved strip is a large enough share of the viewport to push controls into each other, which was measured on four routes at 320px. Phones are also where overlay scrollbars are the norm and the problem does not arise. */
@media (min-width: 640px) {
  :where(html) { scrollbar-gutter: stable; }
}
