/*
 * Base: reset, document typography, type utilities, focus and press
 * feedback. Pi 4 rules apply everywhere: animate transform and opacity only,
 * no blur, no filters, no infinite animations.
 */
@layer base {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    background: var(--surface-0);
  }

  /*
   * Display size (Settings › This device, Stephan 2026-10-11; tokens.css --display-zoom): CSS zoom on the
   * root, not a scale factor in the tokens. Why: the whole interface has to follow, type, spacing, icons,
   * cards, borders and the charts, and some 550 lengths in the style sheets are plain px (a scale token
   * would have to reach every one, and a new one would quietly stay unscaled). Zoom lays the page out
   * anew at the step, unlike a transform: at 90 % the kiosk has the room of a 1138 × 667 screen, text
   * stays sharp, nothing is scaled after the fact. Chromium's zoom is the standardized one since 128 (the
   * kiosk runs 147); measured 2026-10-11 in Chrome 154, at 90 %, 100 % and 110 %:
   * - percentages, fixed insets and the alarm frame, the sheets' scrim and the sleep screen (position:
   *   fixed; inset: 0) fill the screen at every step; viewport units (100dvh) are zoomed like any other
   *   length, so a height of the screen is calc(100dvh / var(--display-zoom)); the safe-area insets
   *   (env()) are zoomed too, and a rule takes tokens.css --safe-*, which divide them (the tab bar, the alarm
   *   frame's corners);
   * - media queries see the screen, not the page: a 1024 px kiosk at 110 % would still take the wide
   *   layout in 931 CSS px. The width breakpoints are therefore container queries on this element
   *   (`@container app`), which see its width in the page's own px; ui/display-zoom.js layoutWidth()
   *   does the same for the two scripts that ask;
   * - getBoundingClientRect(), a pointer's clientX/Y, elementFromPoint() and the window's scroll are in
   *   screen px, an element's scrollTop, offset and client sizes and every length in a style in the
   *   page's px: the scripts that carry a distance from one to the other divide by the zoom
   *   (ui/display-zoom.js; the chart read-outs, the sheet's drag, the on-screen keyboard, the showroom's
   *   drag-to-scroll, the glides).
   * Container queries cannot style their container, so a rule for <html> itself stays a media query
   * (layout.css, the phone's scroll padding).
   */
  html {
    zoom: var(--display-zoom);
    container: app / inline-size;
  }

  html,
  body {
    height: 100%;
  }

  body {
    margin: 0;
    background: var(--surface-0);
    color: var(--text-primary);
    font-family: var(--font-sans);
    font-size: var(--type-body-size);
    line-height: var(--type-body-line);
    letter-spacing: var(--type-body-tracking);
    font-weight: var(--weight-regular);
    font-variant-numeric: tabular-nums;
    font-optical-sizing: auto;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-tap-highlight-color: transparent;
  }

  h1,
  h2,
  h3,
  h4,
  p,
  dl,
  dd,
  figure,
  ul,
  ol {
    margin: 0;
  }

  ul,
  ol {
    padding: 0;
    list-style: none;
  }

  h1,
  h2,
  h3,
  h4 {
    font-size: inherit;
    font-weight: inherit;
  }

  button,
  input,
  select,
  textarea {
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
  }

  button {
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    text-align: inherit;
    cursor: pointer;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
  }

  button:disabled,
  [aria-disabled="true"] {
    cursor: default;
  }

  svg {
    flex: none;
  }

  [hidden] {
    display: none !important;
  }

  /* Focus: visible for keyboard users only. */
  :focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
  }

  :focus:not(:focus-visible) {
    outline: none;
  }

  /* Press feedback on pointer-down, for every pressable element.
     `.is-pressed` is set on pointerdown (src/ui/press.js): with touch
     input Chromium applies :active late or not at all. :active stays as
     the fallback; it lets go once the showroom's mouse drags or holds
     the page (`data-drag-scroll`, showroom/drag-scroll.js), as Chromium
     lets go of it when a finger's scroll starts. */
  button,
  .pressable {
    transition: transform var(--duration-press) ease-out;
  }

  :where(:root:not([data-drag-scroll])) button:not(:disabled):not([aria-disabled="true"]):active,
  button.is-pressed:not(:disabled):not([aria-disabled="true"]),
  :where(:root:not([data-drag-scroll])) .pressable:active,
  .pressable.is-pressed {
    transform: scale(var(--press-scale));
  }

  /* The kiosk normally has no mouse: the pointer is hidden there unless
     the device setting shows it (Settings, "This device"; data-pointer is
     set before the first paint). Everywhere else it always shows. */
  :root[data-device="kiosk"]:not([data-pointer="shown"]),
  :root[data-device="kiosk"]:not([data-pointer="shown"]) * {
    cursor: none !important;
  }

  /* Type utilities: size, leading and tracking always travel together. */
  .type-caption {
    font-size: var(--type-caption-size);
    line-height: var(--type-caption-line);
    letter-spacing: var(--type-caption-tracking);
  }

  .type-body {
    font-size: var(--type-body-size);
    line-height: var(--type-body-line);
    letter-spacing: var(--type-body-tracking);
  }

  .type-headline {
    font-size: var(--type-headline-size);
    line-height: var(--type-headline-line);
    letter-spacing: var(--type-headline-tracking);
  }

  .type-title3 {
    font-size: var(--type-title3-size);
    line-height: var(--type-title3-line);
    letter-spacing: var(--type-title3-tracking);
    font-weight: var(--weight-semibold);
  }

  .type-title2 {
    font-size: var(--type-title2-size);
    line-height: var(--type-title2-line);
    letter-spacing: var(--type-title2-tracking);
    font-weight: var(--weight-semibold);
  }

  .type-title1 {
    font-size: var(--type-title1-size);
    line-height: var(--type-title1-line);
    letter-spacing: var(--type-title1-tracking);
    font-weight: var(--weight-semibold);
  }

  .type-display-s {
    font-size: var(--type-display-s-size);
    line-height: var(--type-display-s-line);
    letter-spacing: var(--type-display-s-tracking);
    font-weight: var(--weight-light);
  }

  .type-display-m {
    font-size: var(--type-display-m-size);
    line-height: var(--type-display-m-line);
    letter-spacing: var(--type-display-m-tracking);
    font-weight: var(--weight-light);
  }

  .type-display-l {
    font-size: var(--type-display-l-size);
    line-height: var(--type-display-l-line);
    letter-spacing: var(--type-display-l-tracking);
    font-weight: var(--weight-light);
  }

  .weight-medium {
    font-weight: var(--weight-medium);
  }

  .weight-semibold {
    font-weight: var(--weight-semibold);
  }

  .text-secondary {
    color: var(--text-secondary);
  }

  .text-tertiary {
    color: var(--text-tertiary);
  }

  .nowrap {
    white-space: nowrap;
  }

  /* Inter's tabular figures also widen the hyphen ("Dichtheits - Test"):
     titles, labels and sentences are words and set proportionally; tabular
     figures stay where numbers stand in columns and count down. */
  .proportional,
  .card-title,
  .sheet-title,
  .header-status-text,
  .toast-text,
  .facts dt,
  .weather-tiles dt,
  .settings-group-title,
  .form-label,
  .list-row-title,
  .svc-row-title {
    font-variant-numeric: normal;
  }

  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The live regions (live-region.js) sit at the end of the body or a
     sheet: pinned to the top corner, so they never add a pixel of scroll
     height. */
  .visually-hidden[data-live-region] {
    top: 0;
    left: 0;
  }

  /* Reduced motion keeps the feedback but drops the scale: a short dim instead. */
  @media (prefers-reduced-motion: reduce) {
    button,
    .pressable {
      transition: opacity var(--duration-press) ease-out;
    }

    :where(:root:not([data-drag-scroll])) button:not(:disabled):not([aria-disabled="true"]):active,
    button.is-pressed:not(:disabled):not([aria-disabled="true"]),
    :where(:root:not([data-drag-scroll])) .pressable:active,
    .pressable.is-pressed {
      transform: none;
      opacity: 0.72;
    }
  }
}
