/* MODULE: css/tutorial.css — the spotlight coach-mark tour (PHASE2 §6).
   Owned by the tutorial agent, consumed only by src/tutorial.js.

   Depends on css/tokens.css for every colour, radius, duration, weight and
   type size, and on the .btn / .btn--primary / .btn--quiet / .u-sr-only
   primitives in css/base.css. Loads nothing: no @import, no fonts, no
   network request of any kind.

   Structure, and why it is four layers rather than one:

     .tut__veil    a plain full-screen dim. Used ONLY for a step that has no
                   target (the closing "install it" card). Blocks pointers.
     .tut__ring    the cutout. It is a transparent box the size of the target
                   with a 200vmax box-shadow spread, so the dim is PAINTED by
                   the ring and the hole is simply where the ring's own box
                   is. pointer-events: none — box-shadow is paint, never
                   hit-testing, so the highlighted control stays live and the
                   user can actually do the thing the card describes.
     .tut__block   four transparent rectangles covering the region OUTSIDE
                   the hole. These are what stop a stray tap landing on the
                   rest of the app. Splitting paint from hit-testing is the
                   whole trick: one element could not do both without either
                   deadening the target or leaking clicks past the dim.
     .tut__card    the coach mark itself — a raised panel, positioned by
                   src/tutorial.js above / below / beside the hole, never
                   over it.

   The dim is a cast shadow, so it darkens in BOTH themes. --ramp-900 is the
   dark end in ceramic; on graphite that role belongs to --ramp-300. The three
   theme selectors below mirror the cascade in css/tokens.css exactly, and the
   split is the same one css/settings.css makes for its scrim. */

/* ============================================================== *
 * 1. ROOT + THEME ATOMS
 * ============================================================== */

.tut {
  position: fixed;
  inset: 0;
  /* Above the settings slide-over (--z-modal). A tour that highlighted the
     settings key and then sat behind the panel would be nonsense. */
  z-index: var(--z-toast);
  /* Clips the ring's 200vmax spread so it can never raise a scrollbar. */
  overflow: hidden;
  /* Inherited by children: each layer opts back in. The card and the blocks
     take pointers; the ring and the tie deliberately do not. */
  pointer-events: none;
  overscroll-behavior: none;

  --tut-dim: color-mix(in oklab, var(--ramp-900) 58%, transparent);
  --tut-edge: color-mix(in oklab, var(--ramp-000) 62%, transparent);
  --tut-gutter: var(--space-4);
  --tut-card-w: 22.5rem; /* 360px */
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="ceramic"]):not([data-theme="graphite"]) .tut {
    --tut-dim: color-mix(in oklab, var(--ramp-300) 76%, transparent);
    --tut-edge: color-mix(in oklab, var(--ramp-900) 34%, transparent);
  }
}

[data-theme="graphite"] .tut {
  --tut-dim: color-mix(in oklab, var(--ramp-300) 76%, transparent);
  --tut-edge: color-mix(in oklab, var(--ramp-900) 34%, transparent);
}

.tut[hidden] {
  display: none;
}

/* ------------------------------------------------------------ probes

   Two invisible rulers, so src/tutorial.js never has to parse a token or
   convert rem to px to know how much room it has.

   .tut__probe is one gutter square: read its width and you have the gutter
   in device pixels, whatever unit the token happens to be written in.

   .tut__safe is the iPhone's safe box — inset on all four sides by the
   env() values css/tokens.css already exposes. One getBoundingClientRect on
   it yields all four insets at once, in viewport coordinates, which is
   exactly the box the card has to stay inside. */

.tut__probe,
.tut__safe {
  position: absolute;
  visibility: hidden;
  pointer-events: none;
}

.tut__probe {
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: var(--tut-gutter);
  block-size: var(--tut-gutter);
}

.tut__safe {
  inset-block-start: var(--safe-top);
  inset-inline-end: var(--safe-right);
  inset-block-end: var(--safe-bottom);
  inset-inline-start: var(--safe-left);
}

/* ============================================================== *
 * 2. THE DIM
 * ============================================================== */

/* Targetless steps only. A step WITH a target is dimmed by the ring's
   spread instead, so there is never a double coat. */
.tut__veil {
  position: absolute;
  inset: 0;
  background-color: var(--tut-dim);
  pointer-events: auto;
  opacity: 0;
  transition: opacity var(--dur-med) var(--ease-out);
}

.tut__veil[hidden] {
  display: none;
}

.tut.is-shown .tut__veil {
  opacity: 1;
}

/* ============================================================== *
 * 3. THE CUTOUT
 *
 *    Positioned at 0,0 and moved with translate3d so the common case is a
 *    composited move; inline-size / block-size still cost a layout pass, but
 *    that happens fifteen times in a session, not sixty times a second. The
 *    dial's frame budget (PHASE3 §4) is never touched by this file.
 * ============================================================== */

.tut__ring {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 0;
  block-size: 0;
  border-radius: var(--radius-m);
  pointer-events: none;
  opacity: 0;
  /* Layer one is the bright lip around the hole — the same 1px edge every
     raised surface in this object carries. Layer two is the dim itself. */
  box-shadow:
    0 0 0 var(--hairline-w) var(--tut-edge),
    0 0 0 200vmax var(--tut-dim);
  transition:
    transform var(--dur-med) var(--ease-out),
    inline-size var(--dur-med) var(--ease-out),
    block-size var(--dur-med) var(--ease-out),
    border-radius var(--dur-med) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}

.tut__ring[hidden] {
  display: none;
}

.tut.is-shown .tut__ring {
  opacity: 1;
}

/* The dial is a circle and its highlight must be one too — a rounded
   rectangle around a disc reads as a mistake. */
.tut__ring[data-shape="circle"] {
  border-radius: var(--radius-pill);
}

.tut__ring[data-shape="pill"] {
  border-radius: var(--radius-pill);
}

/* Four transparent panes covering everything the hole does not. They exist
   for hit-testing alone and paint nothing. */
.tut__block {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 0;
  block-size: 0;
  pointer-events: auto;
  background-color: transparent;
}

/* The hairline tie: a 1px rule running from the card's edge to the hole's,
   the way a Müller-Brockmann caption is anchored to the thing it names.
   Structure, not decoration — it is drawn only when the card sits squarely
   above or below the target. */
.tut__tie {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  /* The width is a hairline and stays one: src/tutorial.js sets only the
     transform and the length, so the rule can never be drawn off-token. */
  inline-size: var(--hairline-w);
  block-size: 0;
  background-color: var(--tut-edge);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.tut__tie[hidden] {
  display: none;
}

.tut.is-shown .tut__tie {
  opacity: 1;
}

/* ============================================================== *
 * 4. THE CARD
 * ============================================================== */

.tut__card {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: min(var(--tut-card-w), calc(100vw - var(--tut-gutter) * 2));
  /* Never taller than the viewport it has to share with the thing it is
     pointing at; the body scrolls inside instead of the page scrolling.
     100vh first as the floor for an engine without dvh, then the real
     measure — 100vh is wrong in mobile Safari and would push the footer
     keys under the browser chrome (PHASE2 §5). */
  max-block-size: calc(100vh - var(--tut-gutter) * 2);
  max-block-size: calc(100dvh - var(--tut-gutter) * 2);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);

  padding: var(--space-4);
  border-radius: var(--radius-l);
  border: var(--hairline-w) solid var(--hairline);
  background-color: var(--bg-raised);
  color: var(--ink);
  box-shadow:
    inset 0 1px 0 var(--tut-edge),
    var(--shadow-raise),
    0 8px 28px color-mix(in oklab, var(--ramp-900) 18%, transparent);

  pointer-events: auto;
  opacity: 0;
  transition:
    transform var(--dur-med) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}

.tut.is-shown .tut__card {
  opacity: 1;
}

/* The card takes focus when a step opens, the same way css/settings.css moves
   focus to its panel. A ring around a whole dialog is noise; the ring belongs
   on the keys inside it, and those keep theirs. */
.tut__card:focus,
.tut__card:focus-visible {
  outline: none;
}

/* ------------------------------------------------------------- head */

.tut__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* "03 / 15". Tabular, because a counter whose digits change width while you
   read it is exactly the sort of small wrongness this app exists to avoid. */
.tut__count {
  font-family: var(--font-num);
  font-size: var(--fs-micro);
  font-weight: var(--wt-medium);
  line-height: var(--lh-micro);
  letter-spacing: var(--tr-micro);
  font-variation-settings: var(--vf-micro);
  font-variant-numeric: var(--font-num-variant);
  font-feature-settings: var(--feat-num);
  text-transform: uppercase;
  color: var(--ink-3);
}

.tut__title {
  font-family: var(--font-sans);
  font-size: var(--fs-title);
  font-weight: var(--wt-medium);
  line-height: var(--lh-title);
  letter-spacing: var(--tr-title);
  font-variation-settings: var(--vf-title);
  color: var(--ink);
  /* Flush left, ragged right. PHASE4 §3 — no exceptions in this file. */
  text-align: start;
  text-wrap: balance;
}

/* ------------------------------------------------------------- body */

.tut__scroll {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.tut__body {
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: var(--wt-regular);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-body);
  font-variation-settings: var(--vf-body);
  color: var(--ink-2);
  max-inline-size: var(--measure);
  text-align: start;
}

.tut__body + .tut__body {
  margin-block-start: var(--space-2);
}

/* The one place a step speaks back to the user: "try it", then "that's it".
   It is a status region, so it changes text without moving anything above it. */
.tut__hint {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: var(--wt-medium);
  line-height: var(--lh-label);
  letter-spacing: var(--tr-label);
  font-variation-settings: var(--vf-label);
  font-feature-settings: var(--feat-caps);
  text-transform: uppercase;
  color: var(--ink-3);
}

.tut__hint[hidden] {
  display: none;
}

.tut__hint::before {
  content: "";
  inline-size: var(--space-2);
  block-size: var(--space-2);
  flex: 0 0 auto;
  align-self: center;
  border-radius: var(--radius-pill);
  background-color: var(--ink-3);
  transition: background-color var(--dur-fast) var(--ease-out);
}

.tut__hint[data-state="done"] {
  color: var(--signal-text);
}

.tut__hint[data-state="done"]::before {
  background-color: var(--signal);
}

/* ------------------------------------------------- the step-1 demo disc */

/* A depleting disc, drawn by this file, driven by src/tutorial.js. It is the
   tutorial's own object — it never touches the real dial, so demonstrating
   cannot disturb a duration the user has already set. */
.tut__demo {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3);
  border-radius: var(--radius-m);
  background-color: var(--bg-sunk);
  box-shadow: var(--shadow-well-s);
}

.tut__demo[hidden] {
  display: none;
}

.tut__demoSvg {
  inline-size: var(--space-8);
  block-size: var(--space-8);
  flex: 0 0 auto;
  overflow: visible;
}

.tut__demoPlate {
  fill: var(--surface);
}

.tut__demoRim {
  fill: none;
  stroke: var(--hairline);
  stroke-width: 1;
}

.tut__demoSector {
  fill: var(--signal);
}

.tut__demoLegend {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-inline-size: 0;
}

.tut__demoValue {
  font-family: var(--font-num);
  font-size: var(--step-1);
  font-weight: var(--wt-light);
  line-height: 1;
  letter-spacing: var(--tr-title);
  font-variation-settings: var(--vf-title);
  font-variant-numeric: var(--font-num-variant);
  font-feature-settings: var(--feat-num);
  color: var(--ink);
}

.tut__demoCaption {
  font-family: var(--font-sans);
  font-size: var(--fs-micro);
  font-weight: var(--wt-medium);
  line-height: var(--lh-micro);
  letter-spacing: var(--tr-micro);
  font-variation-settings: var(--vf-micro);
  font-feature-settings: var(--feat-caps);
  text-transform: uppercase;
  color: var(--ink-3);
}

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

/* A hairline that fills. It tells the user how much tour is left, which is
   the difference between "a few more" and an open-ended demand. */
.tut__rule {
  position: relative;
  block-size: var(--hairline-w);
  background-color: var(--hairline);
  flex: 0 0 auto;
}

.tut__progress {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 0;
  background-color: var(--ink-3);
  transition: inline-size var(--dur-med) var(--ease-out);
}

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

.tut__foot {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}

/* Skip sits alone on the far side of the controls that move you forward, so
   leaving is never something you have to hunt for. */
.tut__skip {
  margin-inline-end: auto;
}

.tut__back[hidden],
.tut__next[hidden] {
  display: none;
}

/* Every key in the footer is a real 44px target on the narrowest phone;
   .btn already guarantees the height, this stops the labels crushing. */
.tut__foot .btn {
  padding-inline: var(--space-3);
}

@media (min-width: 26rem) {
  .tut__foot .btn {
    padding-inline: var(--space-4);
  }
}

/* ============================================================== *
 * 5. NARROW SCREENS
 *    The card is placed by script, but its own metrics tighten so it can
 *    always clear the element it describes on a 320px phone.
 * ============================================================== */

@media (max-width: 26rem) {
  .tut {
    --tut-gutter: var(--space-3);
  }

  .tut__card {
    padding: var(--space-3);
    gap: var(--space-2);
  }

  .tut__demoSvg {
    inline-size: var(--space-7);
    block-size: var(--space-7);
  }
}

/* Not enough height to spare. The demo disc is the first thing to go: the real
   dial is spotlit directly above it on that step, which teaches the same thing
   better, and the words are what must not be pushed into a scroll. */
@media (max-height: 40rem) {
  .tut__demo {
    display: none;
  }
}

/* Short and wide — a phone on its side. Give the card as little height as it
   can live with so there is still room for the thing it is pointing at. */
@media (max-height: 30rem) {
  .tut__card {
    gap: var(--space-2);
    padding: var(--space-3);
  }
}

/* ============================================================== *
 * 6. MOTION, CONTRAST, FORCED COLOURS
 * ============================================================== */

/* PHASE2 §6: jump cuts, no spotlight transitions, no demo animation. The
   global rule in css/base.css already collapses every duration token, but
   these are stated outright so the intent survives a future edit to base. */
@media (prefers-reduced-motion: reduce) {
  .tut__veil,
  .tut__ring,
  .tut__tie,
  .tut__card,
  .tut__progress,
  .tut__demoSector {
    transition: none;
  }
}

@media (prefers-contrast: more) {
  .tut {
    --tut-dim: color-mix(in oklab, var(--ramp-900) 72%, transparent);
  }

  [data-theme="graphite"] .tut {
    --tut-dim: color-mix(in oklab, var(--ramp-300) 92%, transparent);
  }

  .tut__ring {
    box-shadow:
      0 0 0 var(--ring-w) var(--signal),
      0 0 0 200vmax var(--tut-dim);
  }
}

/* box-shadow is dropped entirely in forced-colors, which would take both the
   dim and the lip with it. Give the hole a real border so the spotlight still
   means something, and let the system paint the card. */
@media (forced-colors: active) {
  .tut__card {
    border: 1px solid CanvasText;
    box-shadow: none;
    background-color: Canvas;
  }

  .tut__ring {
    border: 2px solid Highlight;
    box-shadow: none;
  }

  .tut__veil {
    background-color: Canvas;
    opacity: 0.85;
  }

  .tut__tie {
    background-color: CanvasText;
  }

  .tut__demo {
    border: 1px solid CanvasText;
    box-shadow: none;
  }

  .tut__demoSector {
    fill: Highlight;
  }

  .tut__progress {
    background-color: Highlight;
  }
}
