/* ==========================================================================
   tiles.css - the Windows 8 tile system.

   GEOMETRY
   Windows 8's Start grid is built on a 70px cell with a 10px gutter. Every
   official tile size falls out of that one rule:
     small   70×70    = 1×1 cells
     medium  150×150  = 2×2 cells   (2·70 + 10)
     wide    310×150  = 4×2 cells   (4·70 + 3·10)
     large   310×310  = 4×4 cells
   So the grid below is literally `repeat(N, 70px)` with `gap: 10px`, and the
   tile sizes are pure cell spans. Nothing is hand-tuned.
   ========================================================================== */

:root {
  --cell: 70px;
  --gutter: 10px;
  --group-gap: 76px;
}

/* --------------------------------------------------------------------------
   GROUPS
   -------------------------------------------------------------------------- */
.tile-group {
  display: flex;
  flex-direction: column;
  flex: none;
}

.tile-group-header {
  height: 36px;
  display: flex;
  align-items: flex-end;
  padding-bottom: 8px;
  font-family: var(--font-semilight);
  font-weight: 300;
  font-size: 20px;
  line-height: 1;
  color: rgba(255, 255, 255, 0.94);
  cursor: default;
}

/* Column-flow is what makes a Start group wrap downwards first and then
   spill into a new column, instead of behaving like a normal web grid. */
.tile-group-tiles {
  display: grid;
  grid-template-rows: repeat(var(--rows, 6), var(--cell));
  grid-auto-columns: var(--cell);
  grid-auto-flow: column dense;
  gap: var(--gutter);
  align-content: start;
}

/* --------------------------------------------------------------------------
   TILE
   -------------------------------------------------------------------------- */
.tile {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--tile-color, var(--accent));
  color: #fff;
  border: 0;
  padding: 0;
  text-align: left;

  /* The tilt is driven by two custom properties the pointer handler writes.
     Keeping them in the transform means we never rebuild the string in JS. */
  --rx: 0deg;
  --ry: 0deg;
  --tz: 0px;
  --tscale: 1;
  /* Reorder offset, written by the drag FLIP. It leads the chain so it acts
     in the grid's own space, and living here means sliding a tile aside never
     has to overwrite `transform` and clobber the tilt. */
  --fx: 0px;
  --fy: 0px;
  transform:
    translate(var(--fx), var(--fy))
    perspective(620px)
    translateZ(var(--tz))
    rotateX(var(--rx))
    rotateY(var(--ry))
    scale(var(--tscale));
  transform-style: preserve-3d;
  transition: transform 260ms var(--ease-out);
  will-change: transform;
}

.tile-sm { grid-row: span 1; grid-column: span 1; }
.tile-md { grid-row: span 2; grid-column: span 2; }
.tile-wd { grid-row: span 2; grid-column: span 4; }
.tile-lg { grid-row: span 4; grid-column: span 4; }

/* While the pointer is down we snap to the tilt quickly, then ease back
   slowly on release - the asymmetry is what makes the press feel physical. */
.tile.is-pressed { transition: transform 90ms var(--ease-std); }

/* --------------------------------------------------------------------------
   DRAG TO REARRANGE
   -------------------------------------------------------------------------- */

/* The frame in which a tile is measured and re-offset must not animate, or
   FLIP would try to transition to the position it is already leaving. */
.tile.is-flipping { transition: none; }

/* The original stays in the grid while it is up, marking the drop slot. */
.tile.is-drag-source {
  opacity: 0.25;
  pointer-events: none;
}
.tile.is-drag-source .tile-faces,
.tile.is-drag-source .tile-label { visibility: hidden; }

/* The clone that follows the pointer. */
.tile-ghost {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 800;
  margin: 0;
  pointer-events: none;
  transition: none;
  box-shadow: 0 18px 42px rgba(0, 0, 0, 0.45);
  opacity: 0.92;
}
.tile-ghost .tile-check { display: none; }

/* Text selection during a drag turns the whole grid blue. */
body.is-dragging-tile { user-select: none; cursor: grabbing; }
body.is-dragging-tile .tile { cursor: grabbing; }

/* Tiles shuffling out of the way should read as quick and deliberate. The
   260ms the tiles idle at is tuned for the press tilt easing back, which is
   far too slow to keep up with a moving cursor. */
body.is-dragging-tile .tile:not(.is-flipping) {
  transition: transform 165ms var(--ease-out);
}

/* --------------------------------------------------------------------------
   TILE CONTENT
   -------------------------------------------------------------------------- */
.tile-faces {
  position: absolute;
  inset: 0;
}

.tile-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  backface-visibility: hidden;
}

.tile-icon {
  color: #fff;
  opacity: 0.97;
  pointer-events: none;
}
.tile-sm .tile-icon svg { width: 30px; height: 30px; }
.tile-md .tile-icon svg { width: 52px; height: 52px; }
.tile-wd .tile-icon svg { width: 52px; height: 52px; }
.tile-lg .tile-icon svg { width: 76px; height: 76px; }

/* The app name sits bottom-left with a 12px inset. Small tiles never show it. */
.tile-label {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 9px;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.15;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.22);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.tile-sm .tile-label { display: none; }

/* Unread-count badge, bottom-right. */
.tile-badge {
  position: absolute;
  right: 11px;
  bottom: 8px;
  font-family: var(--font-light);
  font-weight: 300;
  font-size: 22px;
  line-height: 1;
  color: #fff;
  pointer-events: none;
}

/* Text-forward live faces (About, Weather, Mail…) use a padded block layout
   rather than the centred-icon layout. */
.tile-face.is-text {
  justify-content: flex-end;
  align-items: flex-start;
  padding: 14px 14px 32px;
}
.tile-face.is-text .tile-face-title {
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 5px;
  opacity: 0.9;
}
.tile-face.is-text .tile-face-body {
  font-size: 14px;
  font-weight: 400;
  line-height: 1.28;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  line-clamp: 4;
  overflow: hidden;
}
.tile-wd .tile-face.is-text .tile-face-body { -webkit-line-clamp: 3; line-clamp: 3; }

/* A face that fills the tile with a photo-ish gradient (Photos live tile). */
.tile-face.is-photo {
  background: linear-gradient(135deg, var(--photo-a, #444), var(--photo-b, #111));
}

/* --------------------------------------------------------------------------
   LIVE TILE TRANSITIONS
   Windows 8 shipped two: a vertical push and a horizontal card flip.
   -------------------------------------------------------------------------- */
.tile-face { transition: transform 520ms var(--ease-out), opacity 520ms var(--ease-out); }

/* -- slide: the outgoing face pushes up and the incoming rises to meet it -- */
.tile-faces[data-anim='slide'] .tile-face                 { transform: translateY(100%); opacity: 0; }
.tile-faces[data-anim='slide'] .tile-face.is-current      { transform: translateY(0);    opacity: 1; }
.tile-faces[data-anim='slide'] .tile-face.is-leaving      { transform: translateY(-100%); opacity: 0; }

/* -- flip: rotates about the horizontal axis through the tile centre ------- */
.tile-faces[data-anim='flip'] { perspective: 420px; transform-style: preserve-3d; }
.tile-faces[data-anim='flip'] .tile-face            { transform: rotateX(-90deg); opacity: 0; }
.tile-faces[data-anim='flip'] .tile-face.is-current { transform: rotateX(0deg);   opacity: 1; }
.tile-faces[data-anim='flip'] .tile-face.is-leaving { transform: rotateX(90deg);  opacity: 0; }

/* --------------------------------------------------------------------------
   ENTRANCE
   On every return to Start the tiles fly in from the right in a diagonal
   wave. `--delay` is set per tile from its grid position.
   -------------------------------------------------------------------------- */
.start-grid.is-entering .tile {
  animation: tile-enter 380ms var(--ease-out) both;
  animation-delay: var(--delay, 0ms);
}

@keyframes tile-enter {
  from { opacity: 0; transform: perspective(620px) translate3d(190px, 0, 0) scale(0.94); }
  to   { opacity: 1; transform: perspective(620px) translate3d(0, 0, 0) scale(1); }
}

.start-grid.is-entering .tile-group-header {
  animation: header-enter 380ms var(--ease-out) both;
  animation-delay: var(--group-delay, 0ms);
}

@keyframes header-enter {
  from { opacity: 0; transform: translateX(120px); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   SELECTION (right-click)
   -------------------------------------------------------------------------- */
.tile.is-selected { outline: 3px solid #fff; outline-offset: -3px; }

.tile-check {
  position: absolute;
  top: 0;
  right: 0;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  background: #fff;
  color: #333;
  transform: scale(0);
  transform-origin: top right;
  transition: transform 140ms var(--ease-out);
  z-index: 2;
}
.tile.is-selected .tile-check { transform: scale(1); }
.tile-check svg { width: 15px; height: 15px; }

/* --------------------------------------------------------------------------
   REMOVAL - unpinning shrinks the tile out and the grid reflows behind it.
   -------------------------------------------------------------------------- */
.tile.is-unpinning {
  animation: tile-unpin 220ms var(--ease-in) both;
  pointer-events: none;
}
@keyframes tile-unpin {
  to { opacity: 0; transform: scale(0.6); }
}

/* --------------------------------------------------------------------------
   LAUNCH - the pressed tile scales up and fades as the app takes over.
   A cloned node does the travelling so grid layout is never disturbed.
   -------------------------------------------------------------------------- */
.tile-launch-clone {
  position: fixed;
  z-index: 200;
  pointer-events: none;
  transform-origin: center;
  animation: tile-launch 300ms var(--ease-out) both;
}
@keyframes tile-launch {
  from { transform: scale(1);   opacity: 1; }
  to   { transform: scale(9);   opacity: 0; }
}

/* A freshly installed tile announces itself, then settles. */
.tile.is-installing {
  animation: tile-install 460ms var(--ease-out) both;
  z-index: 2;
}
@keyframes tile-install {
  0%   { opacity: 0; transform: perspective(620px) scale(0.4); }
  60%  { opacity: 1; transform: perspective(620px) scale(1.06); }
  100% { opacity: 1; transform: perspective(620px) scale(1); }
}
