/* Foundation — the Apple-style skin for every served page.
 *
 * Built from the apple-design reference. Three things it is organised around:
 *
 *   A small, deliberate set of surfaces. The stylesheets it replaces used 54
 *   distinct light background colours, most of them near-identical off-whites
 *   chosen one at a time. That is the opposite of restraint, and it is also
 *   why dark mode was impossible: there was no set of surfaces to invert.
 *   Everything now resolves to seven tiers.
 *
 *   Layout that scales with the text. demo.css had 256 spacing declarations
 *   and not one in rem, so raising the browser text size grew the words and
 *   left the padding behind. Spacing is a rem scale, which means the layout
 *   grows with Dynamic Type rather than tearing.
 *
 *   Size-specific typography. Tracking tightens as type grows and leading
 *   moves the other way, because a single letter-spacing value is wrong
 *   somewhere.
 *
 * Every value is deliberate. Nothing is round for its own sake.
 */

@layer foundation, components;

.site-language-control{display:inline-flex;flex:0 0 auto;align-items:center;gap:.4rem;min-width:0;margin-left:auto;border:1px solid color-mix(in srgb,var(--line-soft,#dbe3ee) 88%,transparent);border-radius:.7rem;padding:.3rem .45rem;background:color-mix(in srgb,var(--surface-raised,#fff) 88%,transparent);color:var(--ink-muted,#5b6d85);box-shadow:0 1px 2px rgba(13,32,54,.05)}
.site-language-control>span{display:grid;width:1.45rem;height:1.45rem;place-items:center;font-size:.72rem;font-weight:750}
.site-language-control select{max-width:9rem;min-height:2rem;border:0;background:transparent;color:var(--ink,#17324f);font:650 .78rem/1 system-ui,sans-serif;cursor:pointer;outline:0}
.site-language-control:focus-within{outline:3px solid color-mix(in srgb,var(--accent,#0071e3) 22%,transparent);outline-offset:2px}
.site-language-control.is-floating{position:fixed;z-index:50;top:1rem;right:1rem;margin:0;background:rgba(255,255,255,.94);backdrop-filter:blur(16px);box-shadow:0 8px 28px rgba(13,32,54,.12)}
@media(max-width:640px){.site-language-control{margin-left:auto}.site-language-control>span{display:none}.site-language-control select{max-width:6.7rem;font-size:.72rem}}

@layer foundation {
  :root {
    /* ── Surfaces ──────────────────────────────────────────────────────
     * Seven tiers, not fifty-four shades. base is the page, raised is what
     * sits on it, sunken is a recess within a raised surface. The tints are
     * semantic: they mean something, they are not decoration. */
    --surface-base: #f4f7fb;
    --surface-raised: #ffffff;
    --surface-sunken: #f6f8fc;
    --tint-info: #eaf1fd;
    --tint-success: #e8f5ee;
    --tint-warning: #fdf4e3;
    --tint-danger: #fdf0ee;
    --line-soft: #dbe3ee;

    /* Ink. Three weights, because a fourth grey is a decision nobody can
     * defend and every extra one flattens the hierarchy. */
    --ink-strong: #0d2036;
    --ink: #17324f;
    --ink-muted: #5b6d85;

    --accent: #0071e3;
    --accent-strong: #0066cc;
    --accent-ink: #ffffff;

    /* ── Space ─────────────────────────────────────────────────────────
     * rem, so the layout scales with the reader's text size instead of
     * holding fixed while the words grow past it. */
    --space-3xs: 0.25rem;
    --space-2xs: 0.5rem;
    --space-xs: 0.75rem;
    --space-s: 1rem;
    --space-m: 1.5rem;
    --space-l: 2rem;
    --space-xl: 3rem;
    --space-2xl: 4.5rem;
    --space-3xl: 6rem;

    /* Gutters shrink on small screens without a breakpoint, so there is no
     * width where the page is suddenly cramped or suddenly loose. */
    --gutter: clamp(1rem, 4vw, 3rem);
    --measure: 68ch;
    --content-max: 70rem;

    /* ── Type ──────────────────────────────────────────────────────────
     * Tracking is size-specific. Leading moves inversely to size. */
    --type-display: clamp(2.5rem, 6.2vw, 4.5rem);
    --tracking-display: -0.026em;
    --leading-display: 1.03;

    --type-title: clamp(1.75rem, 3.6vw, 2.75rem);
    --tracking-title: -0.017em;
    --leading-title: 1.1;

    --type-heading: clamp(1.15rem, 1.6vw, 1.375rem);
    --tracking-heading: -0.008em;
    --leading-heading: 1.28;

    --type-body: clamp(1rem, 0.5vw + 0.9rem, 1.125rem);
    --leading-body: 1.6;

    --type-small: 0.875rem;
    --type-label: 0.6875rem;
    --tracking-label: 0.08em;

    /* ── Controls ──────────────────────────────────────────────────────
     * 44px is the smallest target a finger hits reliably. It is a floor,
     * expressed in rem so it grows with the text rather than staying a
     * thumb-sized target beside thumb-and-a-half text. */
    --control-min: 2.75rem;
    --control-pad-x: 1.125rem;

    /* ── Motion ────────────────────────────────────────────────────────
     * Critically damped. Nothing here is gesture-driven, so nothing
     * overshoots; bounce belongs to motion a finger started. */
    --response-fast: 110ms;
    --response-base: 260ms;
    --response-slow: 440ms;
    --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
    --ease-in: cubic-bezier(0.64, 0.39, 0.78, 0.4);

    /* ── Depth ─────────────────────────────────────────────────────────
     * A tight contact shadow plus a wide ambient one. A single blur reads
     * as a smudge. Bigger surfaces read as thicker. */
    --lift-chip: 0 1px 2px rgba(13, 32, 54, 0.06), 0 2px 6px rgba(13, 32, 54, 0.04);
    --lift-card: 0 1px 2px rgba(13, 32, 54, 0.05), 0 8px 24px -6px rgba(13, 32, 54, 0.10);
    --lift-panel: 0 2px 4px rgba(13, 32, 54, 0.05), 0 28px 60px -18px rgba(13, 32, 54, 0.18);

    --radius-chip: 0.5rem;
    --radius-card: 0.875rem;
    --radius-panel: 1.25rem;
    --radius-pill: 999px;

    /* ── Material ──────────────────────────────────────────────────────
     * Saturation is raised because blur desaturates what is behind it, and
     * the surface should read as glass over colour rather than as fog. */
    --material-chrome: rgba(252, 253, 255, 0.72);
    --material-blur: saturate(180%) blur(20px);
    --material-edge: rgba(255, 255, 255, 0.62);

    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
      system-ui, "Noto Sans TC", "PingFang TC", "Microsoft JhengHei", sans-serif;
    font-synthesis: none;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  /* Dark mode is deliberately not declared yet, and neither is
   * color-scheme: light dark. The seven tiers above are what makes an
   * inversion possible, but demo.css still hardcodes 88 light backgrounds
   * and 108 dark text colours. Flipping the tokens today would give a dark
   * page carrying white cards with invisible text on them, which is worse
   * than a consistent light interface. It lands once those are tokenized.
   */

  * { box-sizing: border-box; }

  html { scrollbar-gutter: stable; }

  body {
    margin: 0;
    background: var(--surface-base);
    color: var(--ink);
    font-size: var(--type-body);
    line-height: var(--leading-body);
    /* No horizontal scroll at any width, ever. */
    overflow-x: clip;
  }

  h1 {
    font-size: var(--type-display);
    line-height: var(--leading-display);
    letter-spacing: var(--tracking-display);
    font-weight: 700;
    color: var(--ink-strong);
  }

  h2 {
    font-size: var(--type-title);
    line-height: var(--leading-title);
    letter-spacing: var(--tracking-title);
    font-weight: 660;
    color: var(--ink-strong);
  }

  h3 {
    font-size: var(--type-heading);
    line-height: var(--leading-heading);
    letter-spacing: var(--tracking-heading);
    font-weight: 640;
    color: var(--ink-strong);
  }

  /* Nothing overflows its container, whatever the content. Long hostnames
   * and pasted URLs are the normal case on these pages, not the edge one. */
  img, svg, video, canvas, table { max-width: 100%; }
  pre, code, kbd { overflow-wrap: anywhere; }

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

@layer components {
  /* Every control clears the 44px floor. Applied by attribute rather than
   * class so it covers markup this stylesheet has never seen. */
  button, [role="button"], input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    min-height: var(--control-min);
    font: inherit;
  }

  /* Standalone links get the floor too. Selected by where they sit rather
   * than by class, so this covers pages this stylesheet has never seen:
   * commercial.html carries a nav of policy links at 18px that no
   * class-based rule would have caught. */
  a[class*="button"], a[class*="btn"],
  nav a, footer a, [class*="links"] > a, [class*="index"] > a {
    min-height: var(--control-min);
    display: inline-flex;
    align-items: center;
  }

  /* A link inside running prose keeps its natural height. Forcing 44px on an
   * inline link tears the line it sits in. The floor is for targets a finger
   * aims at, not for words a reader happens to be able to click. */
  p a, li a, td a, small a {
    min-height: 0;
    display: inline;
  }

  .material-chrome {
    position: sticky;
    top: 0;
    z-index: 30;
    background: var(--material-chrome);
    -webkit-backdrop-filter: var(--material-blur);
    backdrop-filter: var(--material-blur);
    border-bottom: 1px solid var(--line-soft);
    box-shadow: inset 0 1px 0 var(--material-edge);
  }

  .pressable {
    transition:
      transform var(--response-base) var(--ease-out),
      background-color var(--response-base) var(--ease-out),
      box-shadow var(--response-base) var(--ease-out);
  }

  .pressable:active {
    transform: scale(0.972);
    transition-duration: var(--response-fast);
    transition-timing-function: var(--ease-in);
  }
}

/* Reduced motion is a gentler equivalent, not silence: the press still
 * answers, it just stops moving in space. */
@media (prefers-reduced-motion: reduce) {
  @layer components {
    .pressable:active { transform: none; filter: brightness(0.96); }
  }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* Frostier, not merely un-blurred. Dropping the blur while keeping the
 * transparency would leave text sitting over live content. */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --material-chrome: var(--surface-raised);
    --material-blur: none;
    --material-edge: transparent;
  }
}

@media (prefers-contrast: more) {
  :root {
    --material-chrome: var(--surface-raised);
    --material-blur: none;
    --line-soft: var(--ink);
    --lift-chip: none;
    --lift-card: none;
    --lift-panel: none;
  }
}
