/* ==========================================================================
   ESQRD Event Calendar — DailyWin
   Design source: Figma "ESQRD Event Calendar" › section "Done"
     screen/overview  23:2439
     screen/calendar  1:5503
     screen/results   1:7332
   Canvas: 1920 × 1080. All values below are 1:1 with the Figma frame.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fonts
   The italic cuts of PF DinDisplay Pro are real italics baked into the files,
   so they are registered under font-style:normal to stop browsers from
   applying a second, synthetic oblique on top (Figma marks them "not-italic").
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Rex';
  src: url('../fonts/RexBold.woff2?v=2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'Solitreo';
  src: url('../fonts/Solitreo-Regular.woff2?v=2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'PFDin';
  src: url('../fonts/PFDinDisplayPro-Regular.woff2?v=2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'PFDin';
  src: url('../fonts/PFDinDisplayPro-Bold.woff2?v=2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'PFDin';
  src: url('../fonts/PFDinDisplayPro-Black.woff2?v=2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'PFDinIt';
  src: url('../fonts/PFDinDisplayPro-Italic.woff2?v=2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'PFDinIt';
  src: url('../fonts/PFDinDisplayPro-BoldItalic.woff2?v=2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: 'PFDinIt';
  src: url('../fonts/PFDinDisplayPro-BlackItalic.woff2?v=2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: block;
}

/* --------------------------------------------------------------------------
   2. Tokens
   -------------------------------------------------------------------------- */
:root {
  --red: #fe3a3a;
  --paper: #fbfcf7;

  --green: #8ce9b0;      --green-ink: #073e1c;
  --yellow: #ffdf75;     --yellow-ink: #453607;
  --purple: #ca8ce9;     --purple-ink: #4b275d;
  --blue: #8cd4e9;       --blue-ink: #164a59;
  --orange: #f8aa65;     --orange-ink: #49290d;
  --pink: #f3a4a4;       --pink-ink: #531f1f;

  --check: #1ea41b;
  --check-ink: #e2e9d0;

  --gold: #ffdc5e;
  --silver: #beceff;
  --bronze: #ffb291;

  /* fill stack shared by the “current month” card and the “today” day cell */
  --sticker-fill:
    radial-gradient(110px 101px at 50% 50%,
      rgba(254, 58, 58, 0) 34.618%, rgba(254, 58, 58, 0.2) 100%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.045) 0%, rgba(255, 255, 255, 0.1) 100%),
    linear-gradient(0deg, rgba(254, 58, 58, 0.1), rgba(254, 58, 58, 0.1)),
    linear-gradient(0deg, #fbfcf7, #fbfcf7);

  --hairline: rgba(0, 0, 0, 0.15);
  --glass-line: rgba(255, 255, 255, 0.15);

  /* the frosted “pill” used by every nav / filter chip */
  --pill-fill: radial-gradient(50% 50% at 50% 50%,
                rgba(0, 0, 0, 0.4225) 0%, rgba(0, 0, 0, 0.65) 100%);
  /* red wash added to an active pill (Figma: 84.24% × 100% anchored bottom) */
  --pill-active-glow: radial-gradient(84.24% 100% at 50% 100%,
                rgba(254, 58, 58, 0.5) 0%, rgba(152, 35, 35, 0) 100%);
}

/* --------------------------------------------------------------------------
   3. Base + stage scaling
   Everything lives on a 1920×1080 stage that is uniformly scaled to the
   viewport, so the design keeps its exact proportions on any desktop size.
   -------------------------------------------------------------------------- */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: #100c0a;
  overflow: hidden;
}

body {
  font-family: 'PFDin', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* full-bleed background sits outside the scaled stage so it always covers */
.bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.bg__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* bg/overlay-light — radial vignette, ellipse 1509.8 × 1080 anchored top-centre */
.bg__vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(78.635% 100% at 50% 0%,
              rgba(0, 0, 0, 0.35) 73.169%, rgba(0, 0, 0, 1) 100%);
  opacity: 0.65;
}

/* If fit-stage.js never ran, the 1920x1080 stage would be silently cropped by
   overflow:hidden and the title would sit off-screen. Allow scrolling until the
   scale is in place, so nothing is ever unreachable. */
html:not(.dw-scaled) .viewport { overflow: auto; }

.viewport {
  position: relative;
  z-index: 1;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.stage {
  position: relative;
  width: 1920px;
  height: 1080px;
  flex: none;
  transform-origin: center center;
}

/* --------------------------------------------------------------------------
   4. Shared typography helpers
   -------------------------------------------------------------------------- */
/* Figma trims text boxes to the cap-height / alphabetic-baseline box. */
.tb {
  text-box: trim-both cap alphabetic;
}
.rex {
  font-family: 'Rex', 'PFDin', sans-serif;
  font-weight: 700;
  text-transform: lowercase; /* Rex is an all-caps display face */
  line-height: normal;
}
.din {
  font-family: 'PFDinIt', 'PFDin', sans-serif;
  font-style: normal;
  line-height: normal;
}

/* --------------------------------------------------------------------------
   5. Header — big title, badge, arrows, nav
   -------------------------------------------------------------------------- */
/* title + date badge + arrows share one flex row so the badge follows the
   title width exactly the way it does in the Figma frames */
.topbar {
  position: absolute;
  left: 160px;
  top: 38.994px;
  display: flex;
  align-items: flex-start;
  gap: 14px;
}
.header-side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}
.header-arrows { display: flex; gap: 3px; }

.screen-title {
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 149.348px;
  line-height: normal;
  text-transform: lowercase;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
  background: linear-gradient(180deg, #fff 58.014%, #999 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin: 0;
}

.header-badge {
  height: 35px;
  padding: 2px 17px 0 15px;
  border-radius: 9999px;
  background: var(--red);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 16.8px;
  line-height: normal;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
}

.nav-btn {
  width: 46px;
  height: 46px;
  flex: none;
  padding: 10px;
  border-radius: 9999px;
  border: 1px solid var(--hairline);
  background: var(--pill-fill);
  backdrop-filter: blur(48.75px);
  -webkit-backdrop-filter: blur(48.75px);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.15s ease;
}
.nav-btn:hover { filter: brightness(1.35); }
.nav-btn:active { transform: scale(0.94); }
.nav-btn img { width: 24px; height: 24px; display: block; }
.nav-btn--prev img { transform: rotate(180deg); }

.topnav {
  position: absolute;
  top: 86px;
  right: 160px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.pill {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 46px;
  /* 24 px in Figma; the extra .35 compensates for the text-engine difference
     so the pill row measures exactly like the design */
  padding: 10px 24.35px;
  border-radius: 9999px;
  border: 1px solid var(--hairline);
  background: var(--pill-fill);
  backdrop-filter: blur(48.75px);
  -webkit-backdrop-filter: blur(48.75px);
  overflow: hidden;
  text-decoration: none;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.pill:hover { filter: brightness(1.35); }
.pill__icon { width: 24px; height: 24px; display: block; flex: none; }
.pill__label {
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 16px;
  line-height: normal;
  text-transform: uppercase;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}
.pill--icon-only { padding: 10px; width: 46px; }
.pill--active {
  border-color: var(--red);
  background: var(--pill-active-glow), var(--pill-fill);
}
.pill--active .pill__label { color: #fff; }
.pill__indicator {
  position: absolute;
  left: calc(50% + 0.5px);
  transform: translateX(-50%);
  top: 42.5px;
  width: 68px;
  height: 3px;
  border-radius: 9999px;
  background: var(--red);
}
.nav-divider {
  width: 2px;
  height: 20px;
  flex: none;
  border-radius: 9999px;
  border: 1px solid var(--hairline);
  background: var(--pill-fill);
  backdrop-filter: blur(48.75px);
  -webkit-backdrop-filter: blur(48.75px);
}

/* --------------------------------------------------------------------------
   6. Panel (content-wrapper) + dotted texture
   -------------------------------------------------------------------------- */
.panel {
  position: absolute;
  left: 129px;
  top: 144px;
  width: 1662px;
  height: 913.01px;
  border-radius: 32px;
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(0, 0, 0, 0.4875) 0%, rgba(0, 0, 0, 0.75) 100%);
  backdrop-filter: blur(75px);
  -webkit-backdrop-filter: blur(75px);
}
.panel--strong {
  height: 913px;
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(0, 0, 0, 0.5525) 0%, rgba(0, 0, 0, 0.85) 100%);
}

/* Figma strokes sit on the node box and never shift its children, so every
   border in this file is drawn by a ::before overlay instead of a CSS border. */
.panel::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 32px;
  border: 1px solid var(--hairline);
  pointer-events: none;
}

/* 4×4 px squares on a 24 px grid, aligned to the frame origin */
.panel__dots {
  position: absolute;
  inset: 0;
  border-radius: 31px;
  overflow: hidden;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect width='4' height='4' fill='rgba(255,255,255,0.063)'/%3E%3C/svg%3E");
  background-size: 24px 24px;
  background-position: 13px 22px;
}

/* content/bg-panel — the inset hairline frame */
.panel__inset {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 1622px;
  height: 873px;
  border-radius: 22px;
  border: 2px solid var(--glass-line);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   7. Corner stickers + “made by ESQRD” note
   -------------------------------------------------------------------------- */
.sticker { position: absolute; display: flex; align-items: center; justify-content: center; }
.sticker__rot { flex: none; position: relative; overflow: hidden; }
.sticker img { position: absolute; display: block; }

.sticker--coffee { left: 86px; top: 987px; width: 100.60772729px; height: 100.60772729px; }
.sticker--coffee .sticker__rot {
  width: 87.2229px; height: 87.2229px;
  transform: rotate(-170.35deg) scaleY(-1);
}
.sticker--coffee .coffee-group { left: 3.6222px; top: 4.4595px; width: 80.7335px; height: 77.6928px; }
.sticker--coffee .coffee-solid { left: 3.4640px; top: 3.7760px; width: 80.8911px; height: 80.8911px; }
.sticker--coffee .coffee-gloss { left: 0; top: 0; width: 87.2229px; height: 87.2229px; }

.sticker--pen { left: 1639px; top: 959px; width: 109.6917px; height: 109.6917px; }
.sticker--pen .sticker__rot {
  width: 83.4188px; height: 83.4188px;
  transform: rotate(156.59deg) scaleY(-1);
}
.sticker--pen img {
  left: 50%; top: 50%;
  width: 79.9968px; height: 79.9968px;
  transform: translate(-50%, -50%);
}

.brand-note { position: absolute; left: 0; top: 0; width: 1920px; height: 1080px; pointer-events: none; }
.brand-note__box { position: absolute; display: flex; align-items: center; justify-content: center; }
.brand-note__rot { flex: none; transform: rotate(-10.29deg); }
.brand-note__paper { left: 1712.1807px; top: 987.1607px; width: 131.8268px; height: 132.2520px; }
.brand-note__paper img { display: block; width: 113.3141px; height: 113.8423px; }
.brand-note__title { left: 1740.6241px; top: 1034.0304px; width: 86.4850px; height: 51.8575px; }
.brand-note__title span { font-family: 'Solitreo', cursive; font-size: 26.801px; line-height: normal; color: #000; white-space: nowrap; }
.brand-note__kicker { left: 1732.4834px; top: 1024.7896px; width: 59.0291px; height: 31.6492px; }
.brand-note__kicker span { font-family: 'Solitreo', cursive; font-size: 15.634px; line-height: normal; color: #000; white-space: nowrap; }

/* --------------------------------------------------------------------------
   8. Overview screen
   -------------------------------------------------------------------------- */
.ov-heading {
  position: absolute;
  left: 123px;
  top: 123px;
  margin: 0;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 32px;
  line-height: normal;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}

.stat {
  position: absolute;
  height: 45px;
  border-radius: 14px;
}
.stat__value {
  position: absolute;
  left: 5px;
  top: 5px;
  width: 50px;
  height: 35px;
  border-radius: 9px;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 20px;
  line-height: normal;
  text-transform: lowercase;
  text-box: trim-both cap alphabetic;
}
.stat__label {
  position: absolute;
  left: 70px;
  top: 22.5px;
  transform: translateY(-50%);
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 20px;
  line-height: normal;
  text-transform: lowercase;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}
.stat--days   { left: 123px; top: 219px; width: 230px; background: var(--green); }
.stat--months { left: 363px; top: 219px; width: 230px; background: var(--purple); }
.stat--work   { left: 123px; top: 277px; width: 470px; background: var(--orange); }
.stat--days   .stat__value, .stat--days   .stat__label { color: var(--green-ink); }
.stat--months .stat__value, .stat--months .stat__label { color: var(--purple-ink); }
.stat--work   .stat__value, .stat--work   .stat__label { color: var(--orange-ink); }

.month-grid {
  position: absolute;
  left: 123px;
  top: 392px;
  width: 910px;
  height: 398px;
  display: grid;
  grid-template-columns: repeat(4, 220px);
  grid-template-rows: repeat(3, 126px);
  gap: 10px;
}

.mcard {
  position: relative;
  border-radius: 9px;
  background: var(--paper);
  text-decoration: none;
  display: block;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.mcard::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 9px;
  border: 1px solid var(--hairline);
  pointer-events: none;
}
.mcard:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); }
.mcard__name {
  position: absolute;
  left: 14px;
  top: 14px;
  margin: 0;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 24px;
  line-height: normal;
  text-transform: lowercase;
  color: #000;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}
.mcard__days,
.mcard__marks {
  position: absolute;
  top: 102px;
  margin: 0;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 400;
  font-size: 12px;
  line-height: normal;
  color: rgba(0, 0, 0, 0.65);
  white-space: nowrap;
}
.mcard__days { left: 12px; }
.mcard__days b { font-weight: 700; }
.mcard__marks { right: 11px; }
.mcard__badge {
  position: absolute;
  top: 100px;
  right: 5px;
  height: 20px;
  width: 102px;
  padding: 0 5px 0 0;
  border-radius: 9999px;
  border: 3px solid var(--check);
  background: var(--check);
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.65);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 700;
  font-size: 12px;
  line-height: normal;
  color: var(--check-ink);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.65);
  white-space: nowrap;
}
.mcard__pin {
  position: absolute;
  left: 159px;
  top: 5px;
  width: 60px;
  height: 56px;
  display: block;
  z-index: 2;
}

/* current month — the red outline is hand-drawn in the design, so the whole
   shape (fill + stroke) runs through a turbulence displacement filter */
.mcard--current { background: none; }
.mcard--current::before { display: none; }
/* future / locked months — dashed stroke is 10/10, which CSS `dashed` cannot
   express, so it is drawn as an inline SVG rect */
.mcard--future { background: rgba(251, 252, 247, 0.163); }
.mcard--future::before {
  border: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='126'%3E%3Crect x='1' y='1' width='218' height='124' rx='8' ry='8' fill='none' stroke='rgba(255,255,255,0.35)' stroke-width='2' stroke-dasharray='10 10'/%3E%3C/svg%3E");
}
.mcard--current .mcard__badge { top: 99px; }
.mcard--future .mcard__name  { color: rgba(255, 255, 255, 0.85); }
.mcard--future .mcard__days,
.mcard--future .mcard__marks { color: rgba(255, 255, 255, 0.65); }

/* rocket */
.rocket {
  position: absolute;
  left: 862px;
  top: 20px;
  width: 894.757px;
  height: 894.757px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.rocket__rot {
  flex: none;
  position: relative;
  width: 664.295px;
  height: 664.295px;
  overflow: hidden;
  transform: rotate(-62.75deg);
}
.rocket__shadow {
  position: absolute;
  left: 22.5px;
  top: 23px;
  width: 613.9px;
  height: 623.781px;
}
.rocket__shadow img {
  position: absolute;
  inset: -1.04% -1.06%;
  width: 102.12%;
  height: 102.08%;
  display: block;
}
.rocket__img {
  position: absolute;
  left: 4.54px;
  top: 0;
  width: 655.212px;
  height: 655.212px;
  display: block;
}

/* --------------------------------------------------------------------------
   9. Calendar screen
   -------------------------------------------------------------------------- */
.cal-grid {
  position: absolute;
  inset: 1px;
  padding: 30px;
  display: grid;
  grid-template-columns: repeat(7, 220px);
  grid-template-rows: 35px repeat(6, 126px);
  gap: 10px;
}

.wday {
  position: relative;
  height: 35px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 20px;
  line-height: normal;
  text-transform: lowercase;
  text-box: trim-both cap alphabetic;
}
.wday--mon { background: var(--green);  color: var(--green-ink); }
.wday--tue { background: var(--yellow); color: var(--yellow-ink); }
.wday--wed { background: var(--purple); color: var(--purple-ink); }
.wday--thu { background: var(--blue);   color: var(--blue-ink); }
.wday--fri { background: var(--orange); color: var(--orange-ink); }
.wday--sat,
.wday--sun { background: var(--pink);   color: var(--pink-ink); }

/* the x-for wrapper must not become a grid item */
.cal-cell { display: contents; }

/* out-of-month filler — carries the same 45° hatch as the leaderboard rows */
.day--blank {
  position: relative;
  border-radius: 9px;
  background:
    repeating-linear-gradient(135deg,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.085) 1.1px,
      rgba(255, 255, 255, 0) 2.5px,
      rgba(255, 255, 255, 0) 8.8px),
    rgba(255, 255, 255, 0.05);

  display: flex;
  align-items: center;
  justify-content: center;
}
.day--blank::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 9px;
  border: 3px solid rgba(255, 255, 255, 0.1);
}
.day--blank .blank__rot {
  flex: none;
  position: relative;
  width: 64.5263px;
  height: 64.5263px;
  overflow: hidden;
  opacity: 0.5;
  transform: translate(0.31px, 0.67px) rotate(-4.44deg);
}
.day--blank img {
  position: absolute;
  left: 1.45px;
  top: 2.02px;
  width: 61.1863px;
  height: 61.1863px;
  display: block;
}

/* real day cell */
.day {
  position: relative;
  border-radius: 9px;
  background: var(--paper);
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.day::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 9px;
  border: 1px solid var(--hairline);
  pointer-events: none;
}
.day:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); }

.day--weekend {
  background:
    linear-gradient(0deg, rgba(254, 58, 58, 0.05), rgba(254, 58, 58, 0.05)),
    linear-gradient(0deg, rgba(251, 252, 247, 0.85), rgba(251, 252, 247, 0.85));
}
/* completed — rotated green radial straight from Figma */
.day--done {
  background-image:
    url("data:image/svg+xml;utf8,<svg viewBox='0 0 220 126' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><rect x='0' y='0' height='100%25' width='100%25' fill='url(%23g)' opacity='0.2'/><defs><radialGradient id='g' gradientUnits='userSpaceOnUse' cx='0' cy='0' r='10' gradientTransform='matrix(-6.9 7.45 -5.9183 -5.4814 212.5 3.5)'><stop stop-color='rgb(30,164,27)' offset='0'/><stop stop-color='rgb(58,175,55)' offset='0.125'/><stop stop-color='rgb(85,186,82)' offset='0.25'/><stop stop-color='rgb(113,197,110)' offset='0.375'/><stop stop-color='rgb(141,208,137)' offset='0.5'/><stop stop-color='rgb(196,230,192)' offset='0.75'/><stop stop-color='rgb(251,252,247)' offset='1'/></radialGradient></defs></svg>"),
    linear-gradient(0deg, var(--paper), var(--paper));
  background-size: 100% 100%;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
/* today — same hand-drawn sticker outline as the current month card */
.day--today { background: none; backdrop-filter: none; -webkit-backdrop-filter: none; }
.day--today::before { display: none; }

.day__dot { position: absolute; left: 0; top: 0; width: 12px; height: 12px; display: block; }
.day--today .day__dot { display: none; }

/* day number + participants badge share a row so the badge always clears
   one- and two-digit numbers */
.day__head {
  position: absolute;
  left: 14px;
  top: 14px;
  display: flex;
  align-items: flex-start;
  gap: 9.5px;
}
.day__num {
  margin: 0;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 24px;
  line-height: normal;
  text-transform: lowercase;
  color: #000;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}
.day__note {
  position: absolute;
  left: 14px;
  top: 102px;
  margin: 0;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 400;
  font-size: 12px;
  line-height: normal;
  color: rgba(0, 0, 0, 0.65);
  white-space: nowrap;
  max-width: 196px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.day__note--empty { color: rgba(0, 0, 0, 0.25); }

.day__check {
  position: absolute;
  left: 184px;
  top: 10px;
  width: 26px;
  height: 26px;
  border-radius: 9999px;
  border: 3px solid rgba(0, 0, 0, 0.45);
  background: rgba(0, 0, 0, 0.05);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: transform 0.15s ease;
}
.day__check img { width: 16px; height: 16px; display: none; }
.day__check:hover { transform: scale(1.08); }
.day__check--on {
  left: 184px;
  top: 10px;
  width: 26px;
  height: 26px;
  border-color: var(--check);
  background: var(--check);
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.65);
}
.day__check--on img { display: block; }

.day__people {
  margin-top: -2px;
  flex: none;
  height: 25px;
  min-width: 66px;
  padding: 0 7px 0 5px;
  border-radius: 21px;
  background: #fff;
  border: 1px solid var(--hairline);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
.day__people img { width: 12px; height: 12px; display: block; }
.day__people span {
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 12px;
  line-height: normal;
  color: #000;
  white-space: nowrap;
}
.day__people span i { font-style: normal; font-weight: 700; color: rgba(0, 0, 0, 0.5); }

.avatars {
  position: absolute;
  left: 14px;
  top: 62px;
  width: 141px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: center;
}
.avatars--full { top: 39px; width: 191px; }
.avatars img {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 9999px;
  border: 1px solid #fff;
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.65);
  object-fit: cover;
  margin-right: -5px;
  display: block;
}
.avatars img:last-child { margin-right: 0; }

.day__today-badge {
  position: absolute;
  left: 50%;
  top: -11px;
  transform: translateX(-50%);
  height: 25px;
  padding: 0 12px;
  border-radius: 9999px;
  background: var(--red);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 12px;
  line-height: normal;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
}
.day__pin {
  position: absolute;
  left: 159px;
  top: 85px;
  width: 60px;
  height: 56px;
  display: block;
  pointer-events: none;
}
.day__fire {
  position: absolute;
  left: 86.76px;
  top: 6.83px;
  width: 30.485px;
  height: 30.485px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.day__fire span {
  flex: none;
  position: relative;
  width: 26px;
  height: 26px;
  overflow: hidden;
  transform: rotate(11.01deg);
}
.day__fire i {
  position: absolute;
  left: 3.73px;
  top: 0.08px;
  width: 18.535px;
  height: 25.569px;
  overflow: hidden;
  display: block;
}
.day__fire img {
  position: absolute;
  left: -38.73%;
  top: -14.32%;
  width: 177.47%;
  height: 128.64%;
  max-width: none;
  display: block;
}

/* --------------------------------------------------------------------------
   10. Results screen
   -------------------------------------------------------------------------- */
.res-head {
  position: absolute;
  top: 153px;
  transform: translateY(-50%);
  margin: 0;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 32px;
  line-height: normal;
  text-transform: lowercase;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}
.res-head--place    { left: 75px;  color: var(--green);  text-shadow: 0 -23px 75px var(--green),  0 -23px 109.8px var(--green); }
.res-head--employee { left: 255px; color: var(--yellow); text-shadow: 0 -23px 75px var(--yellow), 0 -23px 109.8px var(--yellow); }
.res-head--done     { left: 670px; color: var(--blue);   text-shadow: 0 -23px 75px var(--blue),   0 -23px 109.8px var(--blue); }
.res-head--progress { left: 1579px; transform: translate(-100%, -50%); text-align: right;
                      color: var(--orange); text-shadow: 0 -23px 75px var(--orange), 0 -23px 109.8px var(--orange); }

.filter-tabs {
  position: absolute;
  left: 65px;
  top: 60px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.ftab {
  position: relative;
  display: flex;
  align-items: center;
  height: 46px;
  padding: 10px 23.4px;
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid transparent;
  overflow: hidden;
  cursor: pointer;
  transition: background 0.15s ease;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 16px;
  line-height: normal;
  text-transform: uppercase;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}
.ftab--all { padding: 10px 24.5px; }
.ftab > span { text-box: trim-both cap alphabetic; }
.ftab:hover { background: rgba(255, 255, 255, 0.12); }
.ftab--active {
  border-color: var(--red);
  color: #fff;
  background: var(--pill-active-glow), var(--pill-fill);
  backdrop-filter: blur(48.75px);
  -webkit-backdrop-filter: blur(48.75px);
}
.ftab--active:hover { background: var(--pill-active-glow), var(--pill-fill); }

.rows {
  position: absolute;
  left: 60px;
  top: 190px;
  width: 1542px;
  height: 700px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow: hidden;
}
/* every row carries a fine 45° hatch (≈18 px pitch) from the design */
.row {
  position: relative;
  width: 100%;
  height: 80px;
  flex: none;
  border-radius: 20px;
  border: 2px solid rgba(255, 255, 255, 0.05);
  background:
    repeating-linear-gradient(135deg,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.026) 1.6px,
      rgba(255, 255, 255, 0) 3.4px,
      rgba(255, 255, 255, 0) 17.9px),
    rgba(255, 255, 255, 0.02);
}
.row--gold,
.row--silver,
.row--bronze { background-repeat: repeat, no-repeat; background-size: auto, 100% 100%; }
.row--gold {
  border-color: var(--gold);
  background-image:
    repeating-linear-gradient(135deg,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.026) 1.6px,
      rgba(255, 255, 255, 0) 3.4px,
      rgba(255, 255, 255, 0) 17.9px),
    radial-gradient(100% 4462.6% at 0% 50%,
    rgba(255, 220, 94, 0.15) 0%, rgba(191, 165, 70, 0.1125) 25%,
    rgba(128, 110, 47, 0.075) 50%, rgba(64, 55, 23, 0.0375) 75%,
    rgba(0, 0, 0, 0) 100%);
}
.row--silver {
  border-color: var(--silver);
  background-image:
    repeating-linear-gradient(135deg,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.026) 1.6px,
      rgba(255, 255, 255, 0) 3.4px,
      rgba(255, 255, 255, 0) 17.9px),
    radial-gradient(100% 4462.6% at 0% 50%,
    rgba(190, 206, 255, 0.15) 0%, rgba(143, 155, 191, 0.1125) 25%,
    rgba(95, 103, 128, 0.075) 50%, rgba(48, 52, 64, 0.0375) 75%,
    rgba(0, 0, 0, 0) 100%);
}
.row--bronze {
  border-color: var(--bronze);
  background-image:
    repeating-linear-gradient(135deg,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.026) 1.6px,
      rgba(255, 255, 255, 0) 3.4px,
      rgba(255, 255, 255, 0) 17.9px),
    radial-gradient(100% 4462.6% at 0% 50%,
    rgba(255, 178, 145, 0.15) 0%, rgba(191, 134, 109, 0.1125) 25%,
    rgba(128, 89, 73, 0.075) 50%, rgba(64, 45, 36, 0.0375) 75%,
    rgba(0, 0, 0, 0) 100%);
}

.row__medal {
  position: absolute;
  left: -2px;
  top: -6px;
  width: 80.286px;
  height: 88.702px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.row__medal span {
  flex: none;
  position: relative;
  width: 65.918px;
  height: 76.801px;
  overflow: hidden;
  transform: rotate(-11.85deg);
}
.row__medal img {
  position: absolute;
  left: -46.07px;
  top: -11.93px;
  width: 159.199px;
  height: 106.132px;
  max-width: none;
  display: block;
}
.row--gold .row__medal img { left: -46.64px; top: -14.1px; }

.row__thumb {
  position: absolute;
  left: 52.68px;
  top: 13.03px;
  width: 49.049px;
  height: 49.049px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.row__thumb span {
  flex: none;
  position: relative;
  width: 45.378px;
  height: 45.378px;
  overflow: hidden;
  transform: rotate(-175.15deg) scaleY(-1);
}
.row__thumb img {
  position: absolute;
  left: -0.8px;
  top: -0.71px;
  width: 46.308px;
  height: 46.308px;
  display: block;
}

.row__rank {
  position: absolute;
  left: 28px;
  top: 25px;
  margin: 0;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 36px;
  line-height: normal;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}

.row__person {
  position: absolute;
  left: 193px;
  top: 13px;
  display: flex;
  align-items: center;
  gap: 16px;
}
.row__person img {
  width: 50px;
  height: 50px;
  flex: none;
  border-radius: 10px;
  border: 1.357px solid #fff;
  box-shadow: 0 1.357px 0 0 rgba(0, 0, 0, 0.65);
  object-fit: cover;
  display: block;
}
.row__person span {
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 20px;
  line-height: normal;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}

.row__score {
  position: absolute;
  left: 606px;
  top: 20.5px;
  width: 76px;
  height: 35px;
  border-radius: 9px;
  background: var(--blue);
  display: flex;
  align-items: center;
  padding-left: 13.46px;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 20px;
  line-height: normal;
  text-transform: lowercase;
  color: var(--blue-ink);
  white-space: nowrap;
}
.row__score i { font-style: normal; color: rgba(22, 74, 89, 0.65); }

.row__progress {
  position: absolute;
  left: 896px;
  top: 21px;
  width: 621px;
  height: 35px;
  border-radius: 9px;
  border: 1px solid var(--orange);
  background: rgb(73, 41, 13);
}
.row__fill {
  position: absolute;
  left: 3px;
  top: 3px;
  height: 27px;
  border-radius: 5px;
  background:
    linear-gradient(90deg, rgba(255, 255, 255, 0) 85.702%, rgba(255, 255, 255, 0.2) 100%),
    var(--orange);
  transition: width 0.4s ease;
}
.row__pct {
  position: absolute;
  right: 9.54px;
  top: 16.5px;
  transform: translateY(-50%);
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 20px;
  line-height: normal;
  text-transform: lowercase;
  text-align: right;
  color: var(--orange);
  white-space: nowrap;
  text-box: trim-both cap alphabetic;
}
.row__pct--inside { color: var(--orange-ink); }

.rows__empty {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 24px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.35);
}

/* --------------------------------------------------------------------------
   11. Modals
   -------------------------------------------------------------------------- */
.modal-root {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal-root[hidden] { display: none; }
.modal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(6, 4, 3, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.modal {
  position: relative;
  border-radius: 24px;
  border: 1px solid var(--hairline);
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(24, 17, 13, 0.97) 0%, rgba(8, 5, 4, 0.99) 100%);
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.7);
  padding: 30px 32px 28px;
  color: #fff;
  max-height: 860px;
  display: flex;
  flex-direction: column;
}
.modal::after {
  content: '';
  position: absolute;
  inset: 10px;
  border-radius: 15px;
  border: 2px solid var(--glass-line);
  pointer-events: none;
}
.modal__title {
  margin: 0 0 4px;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 40px;
  line-height: normal;
  text-transform: lowercase;
  color: #fff;
  text-box: trim-both cap alphabetic;
}
.modal__sub {
  margin: 0 0 24px;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: normal;
  color: rgba(255, 255, 255, 0.65);
}
.modal__close {
  position: absolute;
  right: 22px;
  top: 22px;
  width: 34px;
  height: 34px;
  border-radius: 9999px;
  border: 1px solid var(--hairline);
  background: var(--pill-fill);
  color: rgba(255, 255, 255, 0.85);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal__close:hover { filter: brightness(1.4); }

.modal--day { width: 760px; }
.modal__field { margin-bottom: 18px; }
.modal__label {
  display: block;
  margin-bottom: 8px;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 13px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.65);
}
.modal__input {
  width: 100%;
  height: 46px;
  padding: 0 16px;
  border-radius: 12px;
  border: 1px solid var(--glass-line);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font-family: 'PFDin', sans-serif;
  font-size: 15px;
  outline: none;
}
.modal__input:focus { border-color: var(--red); }

.people-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  max-height: 300px;
  overflow-y: auto;
  padding-right: 8px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}
.people-grid::-webkit-scrollbar { width: 6px; }
.people-grid::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); border-radius: 3px; }
.person {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 12px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.04);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.person:hover { background: rgba(255, 255, 255, 0.09); }
.person--on { border-color: var(--check); background: rgba(30, 164, 27, 0.18); }
.person img {
  width: 32px; height: 32px; border-radius: 9999px;
  border: 1px solid #fff; object-fit: cover; flex: none;
}
.person span {
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 13px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.9);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.person__tick {
  margin-left: auto;
  width: 22px; height: 22px;
  border-radius: 9999px;
  border: 3px solid rgba(255, 255, 255, 0.35);
  flex: none;
  display: flex; align-items: center; justify-content: center;
}
.person--on .person__tick { border-color: var(--check); background: var(--check); }
.person__tick img { width: 14px; height: 14px; border: 0; border-radius: 0; display: none; }
.person--on .person__tick img { display: block; }

.modal__actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; flex: none; }
.btn {
  height: 46px;
  padding: 0 26px;
  border-radius: 9999px;
  border: 1px solid var(--hairline);
  background: var(--pill-fill);
  color: rgba(255, 255, 255, 0.85);
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 15px;
  text-transform: uppercase;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.btn:hover { filter: brightness(1.35); }
.btn--primary { background: var(--red); border-color: var(--red); color: #fff; }
.btn--primary:hover { filter: brightness(1.1); }

.modal__error {
  margin: 0 0 14px;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--red);
}
.modal__hint {
  margin: 18px 0 0;
  font-family: 'PFDinIt', sans-serif;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.4);
}

/* toast */
.toast {
  position: absolute;
  left: 50%;
  bottom: 40px;
  transform: translateX(-50%);
  z-index: 60;
  height: 46px;
  padding: 0 24px;
  border-radius: 9999px;
  background: var(--red);
  color: #fff;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 15px;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}
.toast[hidden] { display: none; }

/* --------------------------------------------------------------------------
   12. Fallback when text-box-trim is unavailable (Safari < 26, Firefox)
   Keeps the vertical rhythm close to the Figma cap-height boxes.
   -------------------------------------------------------------------------- */
/* Firefox and Safari have no text-box-trim, so every element above renders with
   its full line box instead of a cap-height box and the glyphs land off the
   design. The previous stub here set translateY(0), which did nothing.
 
   The corrections below were measured in Chrome by probing each element's
   baseline with trimming on and off, then expressed per em so they hold at any
   size. Two constants come out of the fonts:
 
     Rex      cap = ascent, so the baseline does not move; the box grows 0.25em
              downwards. Top-anchored text stays put; centred text rides up
              half the growth, 0.125em.
     PFDin    baseline drops 0.161em and the box grows 0.511em, so centred text
              rides up 0.161 - 0.256 = 0.0945em.
 
   Boxes end up taller than in Chrome, which is harmless here: every one of
   these elements is either absolutely positioned or sits in a fixed-height
   parent. .err__heading is the exception and gets its margin trimmed back. */
/* text-box-trim is Chrome-only, so Firefox and Safari lay these elements out on
   the full line box and the text sits a little lower than the Figma frame.

   Deliberately NOT corrected here. Two attempts made it worse: the engines read
   different tables for line-height:normal (Chrome hhea, Firefox OS/2 win), and
   a correction that is right for the auto-height text elements is wrong for the
   fixed-height chips, where it moves the whole box instead of the glyphs. The
   uncorrected position is a few px low and consistent; a wrong correction is
   worse than that.

   The real fix is to set USE_TYPO_METRICS in the font binaries, after which
   every engine reads 750/-250 and this whole difference disappears with no CSS
   at all. That needs the licensing sorted first. Failing that, it wants a pass
   with a real Firefox open, element by element. */
/* text-box-trim is Chrome-only, so Firefox and Safari lay these elements out on
   the full line box rather than a cap-height box.

   These offsets are usable now only because the font files carry
   USE_TYPO_METRICS with OS/2 v4. Before that, Firefox read winAscent/Descent
   while Chrome read hhea, the two disagreed on line-height:normal, and nothing
   measured in one engine transferred to the other. With typo metrics honoured
   everywhere, both engines resolve the same line box and a single set of numbers
   works. They were measured by probing each element's baseline in Chrome with
   trimming on and off.

   Rex needs nothing when top-anchored: its cap equals its ascent, so the
   baseline does not move. Centred Rex rides up half the box growth, 0.125em.
   PFDin's baseline drops 0.161em top-anchored and rides up 0.0945em centred.

   Elements with a fixed height that centre their text with flex - .stat__value,
   .wday, .row__score - are left alone on purpose: trimming never changed their
   box, so a correction there moves the whole plate instead of the glyphs. That
   was the bug behind "the value rectangles sit too high". */
@supports not (text-box: trim-both cap alphabetic) {
  /* Top-anchored, through margin-top: the entrance animations own transform on
     these elements and would otherwise wipe the correction mid-flight. */
  .ov-heading,
  .row__rank,
  .err__heading    { margin-top: -0.161em; }

  /* Centred. Safe in transform - none of these carry an entrance animation. */
  .stat__label,
  .row__pct        { transform: translateY(calc(-50% + 0.125em)); }
  .res-head        { transform: translateY(calc(-50% + 0.125em)); }
  .res-head--progress { transform: translate(-100%, calc(-50% + 0.125em)); }
  .pill__label,
  .ftab > span     { transform: translateY(0.0945em); }

  /* Its box is taller here, so give the margin back or the buttons drift down */
  .err__heading    { margin-bottom: 4px; }
}





[x-cloak] .modal-root, [x-cloak] .toast { display: none !important; }

/* --------------------------------------------------------------------------
   Hand-drawn "sticker" outline (current month card / today cell).
   The red stroke in the design is a wobbly marker line, not a CSS border, so
   the shape is a generated wavy rounded rect: the fill is clipped to the outer
   edge and the stroke is painted from the matching centre-line path.
   Both consumers are 220 × 126, so one shape serves them.
   -------------------------------------------------------------------------- */
.shape {
  position: absolute;
  inset: 0;
  background: var(--sticker-fill);
  clip-path: path('M9.0 -1.4C11.5 -2.2 14.4 -1.1 17.1 -0.9C19.7 -0.8 22.4 -0.6 25.1 -0.3C27.8 -0.0 30.5 0.3 33.2 0.7C35.8 1.0 38.5 1.9 41.2 1.8C43.9 1.7 46.6 0.8 49.3 0.2C52.0 -0.4 54.6 -1.8 57.3 -2.0C60.0 -2.2 62.7 -1.5 65.4 -1.0C68.1 -0.5 70.7 0.5 73.4 0.9C76.1 1.2 78.8 1.0 81.5 1.0C84.2 1.0 86.9 1.0 89.5 0.8C92.2 0.7 94.9 0.3 97.6 -0.1C100.3 -0.6 103.0 -1.7 105.6 -1.9C108.3 -2.0 111.0 -1.5 113.7 -1.0C116.4 -0.4 119.1 1.2 121.8 1.6C124.4 2.0 127.1 1.7 129.8 1.4C132.5 1.1 135.2 0.1 137.9 -0.2C140.6 -0.6 143.2 -0.6 145.9 -0.8C148.6 -0.9 151.3 -1.2 154.0 -1.2C156.7 -1.2 159.3 -1.0 162.0 -0.6C164.7 -0.1 167.4 1.3 170.1 1.7C172.8 2.0 175.5 2.0 178.1 1.6C180.8 1.2 183.5 -0.4 186.2 -0.9C188.9 -1.5 191.6 -1.6 194.2 -1.5C196.9 -1.4 199.6 -0.7 202.3 -0.4C205.0 -0.1 208.0 -0.4 210.4 0.3C212.7 1.0 215.2 2.1 216.7 3.8C218.1 5.4 218.0 7.9 218.8 10.3C219.5 12.8 220.6 15.7 221.2 18.4C221.7 21.1 222.2 23.7 222.0 26.4C221.7 29.1 220.3 31.8 219.8 34.5C219.2 37.2 218.8 39.9 218.7 42.5C218.6 45.2 219.0 47.9 219.2 50.6C219.4 53.3 219.4 56.0 219.7 58.6C220.0 61.3 220.7 64.0 221.1 66.7C221.4 69.4 222.0 72.1 221.8 74.8C221.5 77.4 220.2 80.1 219.5 82.8C218.9 85.5 218.0 88.2 218.0 90.9C218.0 93.6 219.1 96.2 219.5 98.9C220.0 101.6 220.6 104.3 220.9 107.0C221.1 109.7 221.3 112.3 221.0 115.0C220.6 117.7 220.4 121.5 218.7 123.2C217.1 124.9 213.6 125.3 211.0 125.4C208.4 125.5 205.6 123.9 202.9 123.9C200.3 124.0 197.6 125.1 194.9 125.7C192.2 126.3 189.5 127.6 186.8 127.8C184.2 128.0 181.5 127.3 178.8 127.0C176.1 126.6 173.4 126.0 170.7 125.7C168.0 125.4 165.4 125.4 162.7 125.2C160.0 125.0 157.3 124.5 154.6 124.6C151.9 124.8 149.3 125.4 146.6 125.9C143.9 126.5 141.2 127.9 138.5 128.0C135.8 128.2 133.1 127.6 130.5 127.0C127.8 126.5 125.1 125.1 122.4 124.7C119.7 124.3 117.0 124.6 114.4 124.8C111.7 125.0 109.0 125.4 106.3 125.7C103.6 126.0 100.9 126.1 98.2 126.4C95.6 126.7 92.9 127.5 90.2 127.6C87.5 127.7 84.8 127.4 82.1 126.8C79.4 126.3 76.8 124.7 74.1 124.3C71.4 123.9 68.7 124.1 66.0 124.4C63.3 124.8 60.7 126.2 58.0 126.6C55.3 127.1 52.6 127.1 49.9 127.2C47.2 127.2 44.5 126.9 41.9 126.8C39.2 126.6 36.5 126.6 33.8 126.2C31.1 125.8 28.4 124.8 25.8 124.5C23.1 124.2 20.4 124.1 17.7 124.5C15.0 125.0 12.4 127.1 9.6 127.1C6.9 127.1 2.7 126.3 1.1 124.3C-0.5 122.4 0.0 118.5 -0.0 115.7C-0.1 112.9 0.6 110.3 0.8 107.6C1.0 104.9 1.0 102.3 1.0 99.6C1.0 96.9 1.2 94.2 0.8 91.5C0.5 88.8 -0.7 86.1 -1.2 83.5C-1.6 80.8 -2.2 78.1 -2.0 75.4C-1.7 72.7 -0.2 70.0 0.4 67.4C1.0 64.7 1.7 62.0 1.7 59.3C1.8 56.6 0.9 53.9 0.6 51.2C0.3 48.6 -0.0 45.9 -0.3 43.2C-0.6 40.5 -0.8 37.8 -1.0 35.1C-1.2 32.4 -1.7 29.8 -1.4 27.1C-1.1 24.4 -0.1 21.7 0.5 19.0C1.1 16.3 1.9 13.5 2.1 11.0C2.4 8.4 1.1 5.7 2.3 3.6C3.4 1.5 6.5 -0.6 9.0 -1.4Z');
  pointer-events: none;
}
.shape::after {
  content: '';
  position: absolute;
  inset: -6px;
  background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-6%20-6%20232%20138'%20width='232'%20height='138'%3E%3Cpath%20d='M9.0%200.6C11.3%20-0.3%2014.3%200.9%2016.9%201.1C19.5%201.2%2022.2%201.4%2024.8%201.7C27.4%202.0%2030.1%202.3%2032.7%202.7C35.3%203.0%2038.0%203.9%2040.6%203.8C43.3%203.7%2045.9%202.8%2048.5%202.2C51.2%201.6%2053.8%200.2%2056.4%20-0.0C59.1%20-0.2%2061.7%200.5%2064.3%201.0C67.0%201.5%2069.6%202.5%2072.2%202.9C74.9%203.2%2077.5%203.0%2080.1%203.0C82.8%203.0%2085.4%203.0%2088.0%202.8C90.7%202.7%2093.3%202.3%2096.0%201.9C98.6%201.4%20101.2%200.3%20103.9%200.1C106.5%20-0.0%20109.1%200.5%20111.8%201.0C114.4%201.6%20117.0%203.2%20119.7%203.6C122.3%204.0%20124.9%203.7%20127.6%203.4C130.2%203.1%20132.8%202.1%20135.5%201.8C138.1%201.4%20140.7%201.4%20143.4%201.2C146.0%201.1%20148.6%200.8%20151.3%200.8C153.9%200.8%20156.6%201.0%20159.2%201.4C161.8%201.9%20164.5%203.3%20167.1%203.7C169.7%204.0%20172.4%204.0%20175.0%203.6C177.6%203.2%20180.3%201.6%20182.9%201.1C185.5%200.5%20188.2%200.4%20190.8%200.5C193.4%200.6%20196.1%201.3%20198.7%201.6C201.3%201.9%20204.1%201.9%20206.6%202.3C209.1%202.7%20212.1%202.8%20213.7%204.0C215.4%205.2%20215.9%207.2%20216.8%209.4C217.7%2011.6%20218.6%2014.7%20219.2%2017.3C219.7%2020.0%20220.2%2022.6%20220.0%2025.2C219.7%2027.9%20218.3%2030.5%20217.8%2033.1C217.2%2035.8%20216.8%2038.4%20216.7%2041.0C216.6%2043.7%20217.0%2046.3%20217.2%2049.0C217.4%2051.6%20217.4%2054.2%20217.7%2056.9C218.0%2059.5%20218.7%2062.1%20219.1%2064.8C219.4%2067.4%20220.0%2070.0%20219.8%2072.7C219.5%2075.3%20218.2%2077.9%20217.5%2080.6C216.9%2083.2%20216.0%2085.8%20216.0%2088.5C216.0%2091.1%20217.1%2093.7%20217.5%2096.4C218.0%2099.0%20218.6%20101.6%20218.9%20104.3C219.1%20106.9%20219.1%20109.5%20219.0%20112.2C218.8%20114.9%20219.5%20118.5%20218.1%20120.4C216.8%20122.2%20213.5%20123.1%20211.0%20123.4C208.5%20123.7%20205.7%20121.9%20203.1%20121.9C200.5%20122.0%20197.8%20123.1%20195.2%20123.7C192.6%20124.3%20189.9%20125.6%20187.3%20125.8C184.7%20126.0%20182.0%20125.3%20179.4%20125.0C176.7%20124.6%20174.1%20124.0%20171.5%20123.7C168.8%20123.4%20166.2%20123.4%20163.6%20123.2C160.9%20123.0%20158.3%20122.5%20155.7%20122.6C153.0%20122.8%20150.4%20123.4%20147.8%20123.9C145.1%20124.5%20142.5%20125.9%20139.9%20126.0C137.2%20126.2%20134.6%20125.6%20132.0%20125.0C129.3%20124.5%20126.7%20123.1%20124.0%20122.7C121.4%20122.3%20118.8%20122.6%20116.1%20122.8C113.5%20123.0%20110.9%20123.4%20108.2%20123.7C105.6%20124.0%20103.0%20124.1%20100.3%20124.4C97.7%20124.7%2095.1%20125.5%2092.4%20125.6C89.8%20125.7%2087.2%20125.4%2084.5%20124.8C81.9%20124.3%2079.3%20122.7%2076.6%20122.3C74.0%20121.9%2071.4%20122.1%2068.7%20122.4C66.1%20122.8%2063.4%20124.2%2060.8%20124.6C58.2%20125.1%2055.5%20125.1%2052.9%20125.2C50.3%20125.2%2047.6%20124.9%2045.0%20124.8C42.4%20124.6%2039.7%20124.6%2037.1%20124.2C34.5%20123.8%2031.8%20122.8%2029.2%20122.5C26.6%20122.2%2023.9%20122.1%2021.3%20122.5C18.7%20123.0%2016.1%20124.8%2013.4%20125.1C10.6%20125.5%206.7%20126.1%204.8%20124.7C2.9%20123.3%202.3%20119.2%202.0%20116.6C1.6%20113.9%202.6%20111.3%202.8%20108.7C3.0%20106.0%203.0%20103.4%203.0%20100.8C3.0%2098.1%203.2%2095.5%202.8%2092.9C2.5%2090.2%201.3%2087.6%200.8%2085.0C0.4%2082.3%20-0.2%2079.7%200.0%2077.0C0.3%2074.4%201.8%2071.8%202.4%2069.1C3.0%2066.5%203.7%2063.9%203.7%2061.2C3.8%2058.6%202.9%2056.0%202.6%2053.3C2.3%2050.7%202.0%2048.1%201.7%2045.4C1.4%2042.8%201.2%2040.2%201.0%2037.5C0.8%2034.9%200.3%2032.3%200.6%2029.6C0.9%2027.0%201.9%2024.4%202.5%2021.7C3.1%2019.1%204.1%2016.4%204.1%2013.8C4.2%2011.2%202.2%208.4%203.0%206.2C3.8%204.0%206.7%201.4%209.0%200.6Z'%20fill='none'%20stroke='%23fe3a3a'%20stroke-width='4'%20stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat 0 0 / 232px 138px;
}

/* The medal-row strokes are horizontal gradients in the design (Figma exports
   only their first stop), so they are drawn as a masked gradient ring. Values
   are sampled straight off the reference render. */
.row--gold,
.row--silver,
.row--bronze { border-color: transparent; background-clip: padding-box; }
.row--gold::after,
.row--silver::after,
.row--bronze::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 20px;
  padding: 2px;
  pointer-events: none;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
.row--gold::after   { background: linear-gradient(90deg, rgb(128,114,69) 0%, rgb(125,111,68) 4.5%, rgb(114,103,67) 17%, rgb(90,82,59) 29.4%, rgb(86,77,57) 41.9%, rgb(81,71,51) 54.3%, rgb(69,58,49) 66.8%, rgb(71,62,53) 79.2%, rgb(67,64,61) 91.7%, rgb(66,64,60) 100%); }
.row--silver::after { background: linear-gradient(90deg, rgb(103,104,116) 0%, rgb(102,103,114) 4.5%, rgb(98,95,102) 17%, rgb(94,88,92) 29.4%, rgb(96,86,83) 41.9%, rgb(95,82,73) 54.3%, rgb(86,78,73) 66.8%, rgb(74,64,53) 79.2%, rgb(68,60,51) 91.7%, rgb(65,58,50) 100%); }
.row--bronze::after { background: linear-gradient(90deg, rgb(119,93,78) 0%, rgb(117,91,77) 4.5%, rgb(107,82,71) 17%, rgb(99,78,66) 29.4%, rgb(89,71,62) 41.9%, rgb(87,71,62) 54.3%, rgb(77,64,56) 66.8%, rgb(66,54,46) 79.2%, rgb(59,52,46) 91.7%, rgb(55,50,44) 100%); }

/* --------------------------------------------------------------------------
   Dot-grid masking.
   In the design the dot texture only shows through the gaps: opaque cards
   cover it and translucent ones sit on a background blur that erases it.
   Rather than nesting backdrop-filters (which Chrome renders against an empty
   backdrop root), the dot layer is masked to the gutters of each grid.
   -------------------------------------------------------------------------- */
.panel__dots--overview {
  -webkit-mask-image:
    linear-gradient(90deg, #000 0 123px, transparent 123px 1033px, #000 1033px 100%),
    linear-gradient(180deg, #000 0 392px, transparent 392px 790px, #000 790px 100%),
    linear-gradient(90deg, transparent 0 220px, #000 220px 230px),
    linear-gradient(180deg, transparent 0 126px, #000 126px 136px);
          mask-image:
    linear-gradient(90deg, #000 0 123px, transparent 123px 1033px, #000 1033px 100%),
    linear-gradient(180deg, #000 0 392px, transparent 392px 790px, #000 790px 100%),
    linear-gradient(90deg, transparent 0 220px, #000 220px 230px),
    linear-gradient(180deg, transparent 0 126px, #000 126px 136px);
  -webkit-mask-size: 100% 100%, 100% 100%, 230px 100%, 100% 136px;
          mask-size: 100% 100%, 100% 100%, 230px 100%, 100% 136px;
  -webkit-mask-position: 0 0, 0 0, 123px 0, 0 392px;
          mask-position: 0 0, 0 0, 123px 0, 0 392px;
  -webkit-mask-repeat: no-repeat, no-repeat, repeat, repeat;
          mask-repeat: no-repeat, no-repeat, repeat, repeat;
}
.panel__dots--calendar {
  -webkit-mask-image:
    linear-gradient(90deg, #000 0 31px, transparent 31px 1631px, #000 1631px 100%),
    linear-gradient(180deg, #000 0 31px, transparent 31px 882px, #000 882px 100%),
    linear-gradient(90deg, transparent 0 220px, #000 220px 230px),
    linear-gradient(180deg, transparent 0 66px, #000 66px 76px, transparent 76px 100%),
    linear-gradient(180deg, transparent 0 126px, #000 126px 136px);
          mask-image:
    linear-gradient(90deg, #000 0 31px, transparent 31px 1631px, #000 1631px 100%),
    linear-gradient(180deg, #000 0 31px, transparent 31px 882px, #000 882px 100%),
    linear-gradient(90deg, transparent 0 220px, #000 220px 230px),
    linear-gradient(180deg, transparent 0 66px, #000 66px 76px, transparent 76px 100%),
    linear-gradient(180deg, transparent 0 126px, #000 126px 136px);
  -webkit-mask-size: 100% 100%, 100% 100%, 230px 100%, 100% 100%, 100% 136px;
          mask-size: 100% 100%, 100% 100%, 230px 100%, 100% 100%, 100% 136px;
  -webkit-mask-position: 0 0, 0 0, 31px 0, 0 0, 0 76px;
          mask-position: 0 0, 0 0, 31px 0, 0 0, 0 76px;
  -webkit-mask-repeat: no-repeat, no-repeat, repeat, no-repeat, repeat;
          mask-repeat: no-repeat, no-repeat, repeat, no-repeat, repeat;
}

/* --------------------------------------------------------------------------
   Laravel port additions.
   Not in the Figma frames — appended here rather than woven into the rules
   above so the pixel-matched sections stay untouched.
   -------------------------------------------------------------------------- */

/* Participant search + select-all chip in the day modal. The design has no
   search at all, but the app does, and the roster grows past eyeballing. */
.people-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.people-tools__search { flex: 1 1 auto; }
.people-tools__all { flex: none; padding: 0 20px; }

/* Error pages (404 / 500 / 403). No Figma frame exists for these, so they
   reuse the standard panel, type scale and buttons and stay centred. */
.err {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 200px;
  text-align: center;
}
.err__heading {
  margin: 0 0 18px;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 44px;
  line-height: normal;
  text-transform: uppercase;
  color: #fff;
  text-box: trim-both cap alphabetic;
}
.err__text {
  margin: 0;
  max-width: 760px;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.65);
}
.err__actions { display: flex; gap: 12px; margin-top: 28px; }
.err__actions .btn { text-decoration: none; }
.err__footer {
  margin: 34px 0 0;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.3);
}

/* Initials avatar, shown when an employee has no uploaded photo. Each plate
   copies the box of the <img> it replaces, so adding a real photo later never
   shifts anything. Tint comes in as --ava-bg / --ava-ink from the controller. */
.ava {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ava-bg);
  color: var(--ava-ink);
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  user-select: none;
}
/* day cell: matches .avatars img */
.ava--cell {
  width: 28px;
  height: 28px;
  border-radius: 9999px;
  border: 1px solid #fff;
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.65);
  margin-right: -5px;
  font-size: 11px;
}
.avatars .ava--cell:last-child { margin-right: 0; }
/* leaderboard row: matches .row__person img */
.ava--row {
  width: 50px;
  height: 50px;
  border-radius: 10px;
  border: 1.357px solid #fff;
  box-shadow: 0 1.357px 0 0 rgba(0, 0, 0, 0.65);
  font-size: 18px;
}
/* day modal: matches .person img. Two classes beat `.person span`. */
.person .ava--person {
  width: 32px;
  height: 32px;
  border-radius: 9999px;
  border: 1px solid #fff;
  font-size: 12px;
  text-overflow: clip;
}

/* The leaderboard is a fixed-height frame in the design, which silently clipped
   any roster past eight people. Scroll it instead, styled like .people-grid.

   The container grows by the gutter and pays it back as padding, so the content
   box stays exactly the design's 1542px and the rows keep their geometry — the
   scrollbar lives in the panel's own margin. 1610px right edge still clears
   .panel__inset at 1642px. */
.rows {
  width: 1550px;
  padding-right: 8px;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
  overscroll-behavior: contain;
}
.rows::-webkit-scrollbar { width: 6px; }
.rows::-webkit-scrollbar-track { background: transparent; }
.rows::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); border-radius: 3px; }
.rows::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.4); }

/* ---------------------------------------------------------------------------
   Motion.
   The stage scale is applied from a custom property that fit-stage.js sets
   before first paint, so the 1920x1080 canvas never flashes at full size and
   then snaps down.
   --------------------------------------------------------------------------- */
/* The stage transform is injected by fit-stage.js as a literal value, not read
   from a custom property: with scale(var(--x)) Chrome cannot fold an identity
   transform, so .stage would become a backdrop root even at scale 1 and every
   nested backdrop-filter (.ftab--active, .pill) would sample an empty backdrop
   and go flat. At a real, non-integral scale the transform exists anyway —
   exactly as it did in the prototype. */

/* Cross-document view transitions: the browser cross-fades between pages and
   keeps the named elements put instead of tearing the whole frame down.
   Browsers without support just ignore the at-rule and navigate as before. */
@view-transition { navigation: auto; }

/* Only elements with no backdrop-filter inside them may be named: a
   view-transition-name makes the element a stacking context and a backdrop
   root, and a nested backdrop-filter then samples an empty backdrop. That
   rules out .panel (it holds .ftab--active) and .topnav (it holds .pill) —
   naming either one visibly flattens their frosted fills. The background and
   the corner stickers are identical on every screen, and holding those still
   is what actually stops the page from looking like it jumps. */
.bg              { view-transition-name: dw-bg; }
.sticker--coffee { view-transition-name: dw-coffee; }
.sticker--pen    { view-transition-name: dw-pen; }
.brand-note      { view-transition-name: dw-brand; }

::view-transition-group(dw-bg),
::view-transition-group(dw-coffee),
::view-transition-group(dw-pen),
::view-transition-group(dw-brand) { animation: none; }

/* everything else cross-fades as one snapshot */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 220ms; }

/* Elements the reference frame drew as <button>/<div> are links here (real
   navigation instead of prototype JS), so they pick up the UA underline that
   .pill and .mcard already reset. */
.ftab, .header-badge, .nav-btn { text-decoration: none; }

/* Interaction polish: the frame is a poster, so keep it subtle. */
.nav-btn[disabled] { opacity: 0.4; cursor: default; }
.nav-btn[disabled]:hover { filter: none; }
.nav-btn[disabled]:active { transform: none; }
/* .ftab and .pill are left alone on purpose: both carry backdrop-filter in
   their active state, and listing `transform` in a transition promotes them to
   their own compositing layer, which makes the frosted fill sample an empty
   backdrop and go flat. Only elements without backdrop-filter get the extra
   transition. */
.modal__close, .day__check { transition: background 0.15s ease, border-color 0.15s ease, filter 0.15s ease, transform 0.15s ease; }
.btn { transition: filter 0.15s ease, transform 0.12s ease; }
.btn:active { transform: scale(0.97); }
.btn[disabled] { opacity: 0.55; cursor: default; }
.btn[disabled]:hover { filter: none; }
.btn[disabled]:active { transform: none; }

/* @view-transition is a top-level rule and cannot be nested in @media, so the
   reduced-motion case is handled by killing the snapshot animations instead. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* "+N" counter closing the day cell's avatar grid when the team is bigger than
   the 14 slots the design was drawn for. Without it a third and fourth row of
   faces would spill over .day__note. */
.ava--more {
  background: rgba(0, 0, 0, 0.55);
  color: rgba(255, 255, 255, 0.9);
  border-color: rgba(255, 255, 255, 0.75);
  font-size: 10px;
}

/* ==========================================================================
   MOTION LAYER
   Appended, never woven into the pixel-matched sections above.

   One hard constraint governs everything here: .nav-btn, .pill, .nav-divider,
   .panel, .ftab--active and .modal__scrim all carry backdrop-filter, and
   animating any ANCESTOR of those turns it into a backdrop root, which makes
   the frosted fill sample an empty backdrop and go visibly flat. So .topnav,
   .filter-tabs, .header-arrows, .panel and .modal-root are never animated —
   only the frosted elements themselves, and leaves with nothing frosted inside.

   Every animation settles on the exact design state (identity transform,
   opacity 1) so the resting frame stays pixel-identical to the Figma frames.
   ========================================================================== */

:root {
  /* Enter decelerates, exit accelerates; never linear. */
  --dw-ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
  --dw-ease-in:   cubic-bezier(0.4, 0, 1, 1);
  --dw-ease-std:  cubic-bezier(0.4, 0, 0.2, 1);
  --dw-ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);

  --dw-micro: 140ms;   /* press / toggle feedback */
  --dw-std:   260ms;   /* hover, state change */
  --dw-enter: 420ms;   /* content arriving */
}

/* --------------------------------------------------------------------------
   Loading skeleton
   Reuses the real containers, so only fills and the shimmer live here.
   -------------------------------------------------------------------------- */
.dw-skel {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  border-radius: 31px;
  overflow: hidden;
}
html.dw-ready .dw-skel {
  opacity: 0;
  visibility: hidden;
  transition: opacity 260ms var(--dw-ease-in), visibility 0s linear 260ms;
}
/* Same backstop as the content: a skeleton nothing can dismiss is worse than no
   skeleton, so CSS alone retires it after 3s. */
html.dw-first:not(.dw-ready) .dw-skel { animation: dw-skel-timeout 4s steps(1, end) forwards; }
/* No JS: never show a skeleton that nothing can dismiss. And it is a
   first-arrival device only - on later navigations the page is already marked
   ready before it paints, so there is nothing to cover. */
html:not(.dw-js) .dw-skel,
html:not(.dw-first) .dw-skel { display: none; }

.dw-skel__box {
  position: relative;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.055);
  overflow: hidden;
}
/* One shared sweep, offset per item so the light travels across the grid
   instead of every tile flashing in unison. */
.dw-skel__box::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
    rgba(255, 255, 255, 0) 20%,
    rgba(255, 255, 255, 0.09) 50%,
    rgba(255, 255, 255, 0) 80%);
  transform: translateX(-100%);
  animation: dw-shimmer 1500ms linear infinite;
  animation-delay: calc(var(--i, 0) * -60ms);
}
@keyframes dw-shimmer {
  to { transform: translateX(100%); }
}
@keyframes dw-hold {
  0%, 99% { opacity: 0; }
  100%    { opacity: 1; }
}
@keyframes dw-skel-timeout {
  0%, 99% { opacity: 1; visibility: visible; }
  100%    { opacity: 0; visibility: hidden; }
}

/* the .stat chips borrow their own geometry; kill the coloured fills */
.dw-skel .stat { background: rgba(255, 255, 255, 0.055); border-radius: 14px; }

.dw-skel--h1 { position: absolute; left: 123px; top: 116px; width: 414px; height: 26px; }
.dw-skel--h2 { position: absolute; left: 123px; top: 152px; width: 262px; height: 26px; }
.dw-skel--card { border-radius: 9px; }
.dw-skel--wday { border-radius: 9px; height: 35px; }
.dw-skel--cell { border-radius: 9px; }

.dw-skel--tab { width: 74px; height: 46px; border-radius: 9999px; }
.dw-skel--tab-all { width: 168px; }
.dw-skel--head { position: absolute; left: 60px; top: 138px; width: 1542px; height: 30px; }
.dw-skel__rows {
  position: absolute;
  left: 60px;
  top: 190px;
  width: 1542px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dw-skel--row { height: 80px; border-radius: 20px; flex: none; }

/* Chrome skeleton: title bar plus the three nav pills. Absolutely positioned
   over the stage, so it never touches .topbar or the .topnav flex row. */
.dw-skel--frame {
  position: absolute;
  inset: 0;
  border-radius: 0;
  z-index: 4;
}
/* The frame skeleton sits over the lit background photo, not over the dark
   panel, so a 5% white wash is invisible there. It borrows the pills' own
   dark frosted tone instead. */
.dw-skel--frame .dw-skel__box { background: rgba(0, 0, 0, 0.42); }
.dw-skel--frame .dw-skel__box::after {
  background: linear-gradient(100deg,
    rgba(255, 255, 255, 0) 20%,
    rgba(255, 255, 255, 0.13) 50%,
    rgba(255, 255, 255, 0) 80%);
}

.dw-skel--title   { position: absolute; left: 168px; top: 56px;  width: 292px; height: 92px; border-radius: 14px; }
.dw-skel--navpill { position: absolute; top: 86px; height: 46px; border-radius: 9999px; }
.dw-skel--nav1    { left: 1322px; width: 176px; }
.dw-skel--nav2    { left: 1508px; width: 184px; --i: 1; }
.dw-skel--nav3    { left: 1714px; width: 46px;  --i: 2; }

/* --------------------------------------------------------------------------
   Entrance choreography
   Gated on .dw-js so scripting-off never hides anything, and fired by
   .dw-ready so the reveal starts the moment the skeleton leaves.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  html.dw-first:not(.dw-ready) .screen-title,
  html.dw-first:not(.dw-ready) .header-side,
  html.dw-first:not(.dw-ready) .pill,
  html.dw-first:not(.dw-ready) .nav-divider,
  html.dw-first:not(.dw-ready) .ov-heading,
  html.dw-first:not(.dw-ready) .stat,
  html.dw-first:not(.dw-ready) .mcard,
  html.dw-first:not(.dw-ready) .rocket,
  html.dw-first:not(.dw-ready) .wday,
  html.dw-first:not(.dw-ready) .day,
  html.dw-first:not(.dw-ready) .day--blank,
  html.dw-first:not(.dw-ready) .ftab,
  html.dw-first:not(.dw-ready) .res-head,
  html.dw-first:not(.dw-ready) .row,
  html.dw-first:not(.dw-ready) .sticker,
  html.dw-first:not(.dw-ready) .brand-note {
    /* Not a plain opacity:0. If dw-ready never lands - a stalled font, a JS
       error, a browser that resolves document.fonts.ready differently - the
       content must still appear rather than leaving a blank stage under a
       skeleton. This holds it hidden, then reveals it on its own. */
    animation: dw-hold 4s steps(1, end) forwards;
  }

  /* Staging: the frame arrives first, then the content it holds. Scoped to
     .dw-first, so this plays once when the site is opened and never again on a
     move between screens - repeating it there is what made the interface look
     like it vanished and came back. */
  html.dw-first.dw-ready .screen-title { animation: dw-rise-sm var(--dw-enter) var(--dw-ease-out) backwards; }
  html.dw-first.dw-ready .header-side  { animation: dw-rise-sm var(--dw-enter) var(--dw-ease-out) 60ms backwards; }
  html.dw-first.dw-ready .pill,
  html.dw-first.dw-ready .nav-divider  { animation: dw-rise-sm var(--dw-enter) var(--dw-ease-out) backwards;
                                animation-delay: calc(40ms + var(--i, 0) * 45ms); }
  html.dw-first.dw-ready .sticker,
  html.dw-first.dw-ready .brand-note   { animation: dw-fade 520ms var(--dw-ease-out) 220ms backwards; }

  /* overview */
  html.dw-first.dw-ready .ov-heading { animation: dw-rise var(--dw-enter) var(--dw-ease-out) 120ms backwards; }
  html.dw-first.dw-ready .stat       { animation: dw-pop 380ms var(--dw-ease-back) backwards;
                              animation-delay: calc(190ms + var(--i, 0) * 55ms); }
  html.dw-first.dw-ready .mcard      { animation: dw-rise var(--dw-enter) var(--dw-ease-out) backwards;
                              animation-delay: calc(300ms + var(--i, 0) * 26ms); }
  /* Arc: the rocket drifts in along its own diagonal rather than straight up. */
  html.dw-first.dw-ready .rocket     { animation: dw-rocket 760ms var(--dw-ease-out) 260ms backwards; }

  /* month — the grid fills row by row, so the eye reads it as a calendar */
  html.dw-first.dw-ready .wday       { animation: dw-rise-sm 360ms var(--dw-ease-out) backwards;
                              animation-delay: calc(var(--i, 0) * 34ms); }
  html.dw-first.dw-ready .day,
  html.dw-first.dw-ready .day--blank { animation: dw-rise-sm 340ms var(--dw-ease-out) backwards;
                              animation-delay: calc(220ms + var(--i, 0) * 11ms); }

  /* summary */
  html.dw-first.dw-ready .ftab     { animation: dw-rise-sm 340ms var(--dw-ease-out) backwards;
                            animation-delay: calc(var(--i, 0) * 26ms); }
  html.dw-first.dw-ready .res-head { animation: dw-fade 360ms var(--dw-ease-out) 220ms backwards; }
  html.dw-first.dw-ready .row      { animation: dw-rise var(--dw-enter) var(--dw-ease-out) backwards;
                            animation-delay: calc(280ms + var(--i, 0) * 44ms); }
  /* Storytelling: the bar earns its length instead of appearing at full width. */
  html.dw-first.dw-ready .row__fill { transform-origin: left center;
                             animation: dw-fill 720ms var(--dw-ease-out) backwards;
                             animation-delay: calc(420ms + var(--i, 0) * 44ms); }
}

@keyframes dw-fade    { from { opacity: 0; }                              to { opacity: 1; } }
@keyframes dw-rise-sm { from { opacity: 0; transform: translateY(6px); }  to { opacity: 1; transform: none; } }
@keyframes dw-rise    { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes dw-pop     { from { opacity: 0; transform: scale(0.9); }       to { opacity: 1; transform: none; } }
@keyframes dw-fill    { from { transform: scaleX(0); }                    to { transform: scaleX(1); } }
@keyframes dw-rocket  { from { opacity: 0; transform: translate(26px, 34px) scale(0.965); }
                        to   { opacity: 1; transform: none; } }

/* --------------------------------------------------------------------------
   Micro-interactions
   Each one answers "what does this communicate?" — feedback on press,
   hierarchy on hover, state change on toggle. Nothing loops forever.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  /* Press feedback. Squash keeps volume: as Y compresses, X gives a little. */
  .btn:active            { transform: scale(1.02, 0.94); }
  .pill:active,
  .ftab:active           { transform: scale(0.975); }
  .nav-btn:not([disabled]):active { transform: scale(0.92); }
  .mcard:active          { transform: translateY(-1px) scale(0.994); }
  .day:active            { transform: translateY(-1px) scale(0.995); }

  /* Secondary action: the pin reacts to the card it is pinned to. */
  .mcard__pin, .day__pin { transition: transform var(--dw-std) var(--dw-ease-back); }
  .mcard:hover .mcard__pin { transform: rotate(-7deg) translateY(-1px); }
  .day:hover  .day__pin    { transform: rotate(6deg) translateY(-1px); }

  /* Participants lift together, with follow-through across the row. */
  .avatars img, .avatars .ava { transition: transform var(--dw-std) var(--dw-ease-back); }
  .day:hover .avatars img,
  .day:hover .avatars .ava    { transform: translateY(-2px); }

  /* Leaderboard: the row lifts, the medal catches the light. Base rotation is
     preserved — reordering these transforms sends the ribbon the wrong way. */
  .row { transition: transform var(--dw-std) var(--dw-ease-out); }
  .row:hover { transform: translateX(3px); }
  .row__medal span, .row__thumb span { transition: transform var(--dw-std) var(--dw-ease-back); }
  .row:hover .row__medal span { transform: rotate(-11.85deg) scale(1.07); }
  .row:hover .row__thumb span { transform: rotate(-175.15deg) scaleY(-1) scale(1.09); }
  .row__person img, .row__person .ava { transition: transform var(--dw-std) var(--dw-ease-back); }
  .row:hover .row__person img,
  .row:hover .row__person .ava { transform: scale(1.06); }

  /* Day toggle: the tick pops on the way in, so marking a day feels landed. */
  .day__check       { transition: transform var(--dw-micro) var(--dw-ease-back),
                                  background var(--dw-std) var(--dw-ease-std),
                                  border-color var(--dw-std) var(--dw-ease-std); }
  .day__check:active { transform: scale(0.86); }
  .day__check--on img { animation: dw-tick 320ms var(--dw-ease-back) backwards; }

  /* Modal participant rows */
  .person        { transition: background var(--dw-std) var(--dw-ease-std),
                               border-color var(--dw-std) var(--dw-ease-std),
                               transform var(--dw-micro) var(--dw-ease-back); }
  .person:active { transform: scale(0.985); }
  .person__tick  { transition: background var(--dw-std) var(--dw-ease-std),
                               border-color var(--dw-std) var(--dw-ease-std); }
  .person--on .person__tick img { animation: dw-tick 280ms var(--dw-ease-back) backwards; }

  /* The modal's own enter/exit is driven by Alpine (see the day and login
     partials), because a CSS animation here would fire once on page load while
     the dialog is still hidden and never again on open. */
}

@keyframes dw-tick  { from { opacity: 0; transform: scale(0.4); } to { opacity: 1; transform: none; } }

/* --------------------------------------------------------------------------
   Page transitions
   boot.js tags each navigation with a type, so the motion carries one
   consistent spatial model: into a month is forward, back to the year is back,
   month stepping is sideways, and the two nav tabs simply cross-fade.
   Exit accelerates away, enter decelerates in.
   -------------------------------------------------------------------------- */
::view-transition-group(root) { animation-duration: 320ms; }

html:active-view-transition-type(dw-forward)::view-transition-old(root) {
  animation: dw-vt-out-left 200ms var(--dw-ease-in) both;
}
html:active-view-transition-type(dw-forward)::view-transition-new(root) {
  animation: dw-vt-in-right 340ms var(--dw-ease-out) both;
}
html:active-view-transition-type(dw-back)::view-transition-old(root) {
  animation: dw-vt-out-right 190ms var(--dw-ease-in) both;
}
html:active-view-transition-type(dw-back)::view-transition-new(root) {
  animation: dw-vt-in-left 320ms var(--dw-ease-out) both;
}
html:active-view-transition-type(dw-next)::view-transition-old(root) {
  animation: dw-vt-out-left 180ms var(--dw-ease-in) both;
}
html:active-view-transition-type(dw-next)::view-transition-new(root) {
  animation: dw-vt-in-right 300ms var(--dw-ease-out) both;
}
html:active-view-transition-type(dw-prev)::view-transition-old(root) {
  animation: dw-vt-out-right 180ms var(--dw-ease-in) both;
}
html:active-view-transition-type(dw-prev)::view-transition-new(root) {
  animation: dw-vt-in-left 300ms var(--dw-ease-out) both;
}

@keyframes dw-vt-out-left  { to   { opacity: 0; transform: translateX(-2.2%) scale(0.985); } }
@keyframes dw-vt-in-right  { from { opacity: 0; transform: translateX(2.8%)  scale(0.985); } }
@keyframes dw-vt-out-right { to   { opacity: 0; transform: translateX(2.2%)  scale(0.985); } }
@keyframes dw-vt-in-left   { from { opacity: 0; transform: translateX(-2.8%) scale(0.985); } }

/* Modal enter/exit, applied by Alpine as classes on the sheet itself (the root
   only cross-fades). Anticipation on the way in, faster and flatter on the way
   out, because closing should not make the user wait. */
@media (prefers-reduced-motion: no-preference) {
  .dw-anim-modal-in  { animation: dw-modal-in  300ms var(--dw-ease-back); }
  .dw-anim-modal-out { animation: dw-modal-out 180ms var(--dw-ease-in) forwards; }
}
@keyframes dw-modal-in  { from { opacity: 0; transform: translateY(12px) scale(0.97); }
                          to   { opacity: 1; transform: none; } }
@keyframes dw-modal-out { from { opacity: 1; transform: none; }
                          to   { opacity: 0; transform: translateY(6px) scale(0.99); } }

/* --------------------------------------------------------------------------
   Modal dimming
   The scrim lives inside .stage so the dialog, which is also in there, still
   paints above it. But .stage is a scaled box, so inset:0 only ever covered the
   design area and stopped at the letterbox edge. Growing it by the inverse of
   the stage scale makes one layer that covers the whole viewport and dims the
   calendar with it - two stacked layers would double-darken where they meet.
   -------------------------------------------------------------------------- */
.modal__scrim {
  inset: auto;
  left: 50%;
  top: 50%;
  width: calc(100vw / var(--dw-scale, 1));
  height: calc(100vh / var(--dw-scale, 1));
  transform: translate(-50%, -50%);
}

/* The score chip's caps sat about 2.5px above the optical centre of its 35px
   box. text-box cannot fix it: .row__score is a flex container and its text is
   in an anonymous flex item the property never reaches. So the children are
   nudged instead.

   Only where trimming is supported, because the misalignment is Chrome-only
   arithmetic: with hhea metrics Rex's line box is 1.0em, so centring a 20px box
   in 35px puts the cap centre at 15px against a box centre of 17.5px. Firefox
   uses win metrics, gets a 1.241em line box, and lands the cap centre at 17.47px
   which is already right, so it must be left alone. */


/* The month badge is width:102px in the frame, which is exactly enough for the
   single-digit case it was drawn with. "31 дня отмечено" needs about 103px
   against the 97px left after the right padding, so the text escaped the green
   pill. min-width keeps the drawn size for short labels and lets it grow only
   when it has to; max-width stops it running past the card edge. */
.mcard__badge {
  /* max-content, not auto. The text is an anonymous flex item, and shrink-to-fit
     resolved it to 102.016px while the text itself needed 96px plus the 5px
     right padding and 6px of border - 5px short, so it spilled past the left
     edge. max-content sizes the box to what the text actually needs.
     content-box is the other half of it: under the global border-box, width
     sizes the OUTER box, so the 5px padding and 6px border ate into the text's
     own allowance and it stayed 5px short however the width was expressed.
     With content-box the text gets its full max-content and the padding and
     border add around it.

     Sizes are content-box now: min-width 91px is the frame's 102px minus the
     11px of padding and border, and max-width 199px keeps the outer box inside
     the 220px card with the 5px offset and a little clearance. */
  width: auto;
  min-width: 0;
  max-width: 210px;
  padding: 0 7px;
}

/* Same reasoning for the participants pill in a day cell: it already had a
   min-width, but the count can reach three digits on a large team. */
.day__people { max-width: 130px; }

/* --------------------------------------------------------------------------
   Optical centring of numerals in fixed-height chips

   Rex's cap is 0.750em inside a 1.000em line box, so the 0.250em of descender
   space it never uses sits inside the box and pushes the caps 2.5px above the
   optical centre of a 35px chip. text-box cannot reach these: each one is a
   flex container whose text lives in an anonymous flex item.

   padding-top does reach them. With border-box the height is unchanged, the
   content box shrinks, and centring inside it moves the caps down by half the
   padding - 2.5px, which lands the cap centre exactly on the box centre.

   Unconditional now. Before USE_TYPO_METRICS was set on the fonts, Firefox read
   win metrics, got a 1.241em line box and happened to centre correctly, so this
   would have broken it. With both engines on typo metrics they share the same
   1.000em box and the same correction.
   -------------------------------------------------------------------------- */
.stat__value { padding-top: 5px; }
.wday        { padding-top: 5px; }
.row__score  { padding-top: 5px; }

/* Same effect at PFDin's 0.689em cap in a 1.200em box, scaled to the 25px pill */
.day__people { padding-top: 2px; }

/* --------------------------------------------------------------------------
   Stage scaling without JavaScript

   The scale is normally set by the inline script in the layout. This is what
   happens when that never runs - a script blocker, an injected CSP, an
   extension that rewrites the page. Without it the 1920x1080 canvas renders at
   natural size and gets cropped top and bottom, which is what a browser profile
   with extensions was doing while the same machine was fine in incognito.

   The canvas is 16:9, so above that aspect ratio the fit depends only on the
   viewport height and below it only on the width. That makes it expressible as
   stepped media queries. Every value is rounded DOWN, so the worst case is a few
   px of extra letterbox rather than a single px of cropping.

   Only applies while .dw-scaled is absent: the moment the script runs it sets
   the exact value and this stands down. Frosted fills flatten under a var()
   transform, which is a fair trade for a page that is otherwise unusable.
   -------------------------------------------------------------------------- */
html:not(.dw-scaled) .stage { transform: scale(var(--dw-css-scale, 1)); }

/* wider than 16:9 - height decides */
@media (min-aspect-ratio: 16/9) {
  @media (min-height: 360px) { html:not(.dw-scaled) { --dw-css-scale: 0.333; } }
  @media (min-height: 380px) { html:not(.dw-scaled) { --dw-css-scale: 0.351; } }
  @media (min-height: 400px) { html:not(.dw-scaled) { --dw-css-scale: 0.370; } }
  @media (min-height: 420px) { html:not(.dw-scaled) { --dw-css-scale: 0.388; } }
  @media (min-height: 440px) { html:not(.dw-scaled) { --dw-css-scale: 0.407; } }
  @media (min-height: 460px) { html:not(.dw-scaled) { --dw-css-scale: 0.425; } }
  @media (min-height: 480px) { html:not(.dw-scaled) { --dw-css-scale: 0.444; } }
  @media (min-height: 500px) { html:not(.dw-scaled) { --dw-css-scale: 0.462; } }
  @media (min-height: 520px) { html:not(.dw-scaled) { --dw-css-scale: 0.481; } }
  @media (min-height: 540px) { html:not(.dw-scaled) { --dw-css-scale: 0.500; } }
  @media (min-height: 560px) { html:not(.dw-scaled) { --dw-css-scale: 0.518; } }
  @media (min-height: 580px) { html:not(.dw-scaled) { --dw-css-scale: 0.537; } }
  @media (min-height: 600px) { html:not(.dw-scaled) { --dw-css-scale: 0.555; } }
  @media (min-height: 620px) { html:not(.dw-scaled) { --dw-css-scale: 0.574; } }
  @media (min-height: 640px) { html:not(.dw-scaled) { --dw-css-scale: 0.592; } }
  @media (min-height: 660px) { html:not(.dw-scaled) { --dw-css-scale: 0.611; } }
  @media (min-height: 680px) { html:not(.dw-scaled) { --dw-css-scale: 0.629; } }
  @media (min-height: 700px) { html:not(.dw-scaled) { --dw-css-scale: 0.648; } }
  @media (min-height: 720px) { html:not(.dw-scaled) { --dw-css-scale: 0.666; } }
  @media (min-height: 740px) { html:not(.dw-scaled) { --dw-css-scale: 0.685; } }
  @media (min-height: 760px) { html:not(.dw-scaled) { --dw-css-scale: 0.703; } }
  @media (min-height: 780px) { html:not(.dw-scaled) { --dw-css-scale: 0.722; } }
  @media (min-height: 800px) { html:not(.dw-scaled) { --dw-css-scale: 0.740; } }
  @media (min-height: 820px) { html:not(.dw-scaled) { --dw-css-scale: 0.759; } }
  @media (min-height: 840px) { html:not(.dw-scaled) { --dw-css-scale: 0.777; } }
  @media (min-height: 860px) { html:not(.dw-scaled) { --dw-css-scale: 0.796; } }
  @media (min-height: 880px) { html:not(.dw-scaled) { --dw-css-scale: 0.814; } }
  @media (min-height: 900px) { html:not(.dw-scaled) { --dw-css-scale: 0.833; } }
  @media (min-height: 920px) { html:not(.dw-scaled) { --dw-css-scale: 0.851; } }
  @media (min-height: 940px) { html:not(.dw-scaled) { --dw-css-scale: 0.870; } }
  @media (min-height: 960px) { html:not(.dw-scaled) { --dw-css-scale: 0.888; } }
  @media (min-height: 980px) { html:not(.dw-scaled) { --dw-css-scale: 0.907; } }
  @media (min-height: 1000px) { html:not(.dw-scaled) { --dw-css-scale: 0.925; } }
  @media (min-height: 1020px) { html:not(.dw-scaled) { --dw-css-scale: 0.944; } }
  @media (min-height: 1040px) { html:not(.dw-scaled) { --dw-css-scale: 0.962; } }
  @media (min-height: 1060px) { html:not(.dw-scaled) { --dw-css-scale: 0.981; } }
  @media (min-height: 1080px) { html:not(.dw-scaled) { --dw-css-scale: 1.000; } }
  @media (min-height: 1100px) { html:not(.dw-scaled) { --dw-css-scale: 1.018; } }
  @media (min-height: 1120px) { html:not(.dw-scaled) { --dw-css-scale: 1.037; } }
  @media (min-height: 1140px) { html:not(.dw-scaled) { --dw-css-scale: 1.055; } }
  @media (min-height: 1160px) { html:not(.dw-scaled) { --dw-css-scale: 1.074; } }
  @media (min-height: 1180px) { html:not(.dw-scaled) { --dw-css-scale: 1.092; } }
  @media (min-height: 1200px) { html:not(.dw-scaled) { --dw-css-scale: 1.111; } }
  @media (min-height: 1220px) { html:not(.dw-scaled) { --dw-css-scale: 1.129; } }
  @media (min-height: 1240px) { html:not(.dw-scaled) { --dw-css-scale: 1.148; } }
  @media (min-height: 1260px) { html:not(.dw-scaled) { --dw-css-scale: 1.166; } }
  @media (min-height: 1280px) { html:not(.dw-scaled) { --dw-css-scale: 1.185; } }
  @media (min-height: 1300px) { html:not(.dw-scaled) { --dw-css-scale: 1.203; } }
  @media (min-height: 1320px) { html:not(.dw-scaled) { --dw-css-scale: 1.222; } }
  @media (min-height: 1340px) { html:not(.dw-scaled) { --dw-css-scale: 1.240; } }
  @media (min-height: 1360px) { html:not(.dw-scaled) { --dw-css-scale: 1.259; } }
  @media (min-height: 1380px) { html:not(.dw-scaled) { --dw-css-scale: 1.277; } }
  @media (min-height: 1400px) { html:not(.dw-scaled) { --dw-css-scale: 1.296; } }
  @media (min-height: 1420px) { html:not(.dw-scaled) { --dw-css-scale: 1.314; } }
  @media (min-height: 1440px) { html:not(.dw-scaled) { --dw-css-scale: 1.333; } }
  @media (min-height: 1460px) { html:not(.dw-scaled) { --dw-css-scale: 1.351; } }
  @media (min-height: 1480px) { html:not(.dw-scaled) { --dw-css-scale: 1.370; } }
  @media (min-height: 1500px) { html:not(.dw-scaled) { --dw-css-scale: 1.388; } }
  @media (min-height: 1520px) { html:not(.dw-scaled) { --dw-css-scale: 1.407; } }
  @media (min-height: 1540px) { html:not(.dw-scaled) { --dw-css-scale: 1.425; } }
  @media (min-height: 1560px) { html:not(.dw-scaled) { --dw-css-scale: 1.444; } }
  @media (min-height: 1580px) { html:not(.dw-scaled) { --dw-css-scale: 1.462; } }
  @media (min-height: 1600px) { html:not(.dw-scaled) { --dw-css-scale: 1.481; } }
}
/* narrower than 16:9 - width decides */
@media (max-aspect-ratio: 16/9) {
  @media (min-width: 320px) { html:not(.dw-scaled) { --dw-css-scale: 0.166; } }
  @media (min-width: 350px) { html:not(.dw-scaled) { --dw-css-scale: 0.182; } }
  @media (min-width: 380px) { html:not(.dw-scaled) { --dw-css-scale: 0.197; } }
  @media (min-width: 410px) { html:not(.dw-scaled) { --dw-css-scale: 0.213; } }
  @media (min-width: 440px) { html:not(.dw-scaled) { --dw-css-scale: 0.229; } }
  @media (min-width: 470px) { html:not(.dw-scaled) { --dw-css-scale: 0.244; } }
  @media (min-width: 500px) { html:not(.dw-scaled) { --dw-css-scale: 0.260; } }
  @media (min-width: 530px) { html:not(.dw-scaled) { --dw-css-scale: 0.276; } }
  @media (min-width: 560px) { html:not(.dw-scaled) { --dw-css-scale: 0.291; } }
  @media (min-width: 590px) { html:not(.dw-scaled) { --dw-css-scale: 0.307; } }
  @media (min-width: 620px) { html:not(.dw-scaled) { --dw-css-scale: 0.322; } }
  @media (min-width: 650px) { html:not(.dw-scaled) { --dw-css-scale: 0.338; } }
  @media (min-width: 680px) { html:not(.dw-scaled) { --dw-css-scale: 0.354; } }
  @media (min-width: 710px) { html:not(.dw-scaled) { --dw-css-scale: 0.369; } }
  @media (min-width: 740px) { html:not(.dw-scaled) { --dw-css-scale: 0.385; } }
  @media (min-width: 770px) { html:not(.dw-scaled) { --dw-css-scale: 0.401; } }
  @media (min-width: 800px) { html:not(.dw-scaled) { --dw-css-scale: 0.416; } }
  @media (min-width: 830px) { html:not(.dw-scaled) { --dw-css-scale: 0.432; } }
  @media (min-width: 860px) { html:not(.dw-scaled) { --dw-css-scale: 0.447; } }
  @media (min-width: 890px) { html:not(.dw-scaled) { --dw-css-scale: 0.463; } }
  @media (min-width: 920px) { html:not(.dw-scaled) { --dw-css-scale: 0.479; } }
  @media (min-width: 950px) { html:not(.dw-scaled) { --dw-css-scale: 0.494; } }
  @media (min-width: 980px) { html:not(.dw-scaled) { --dw-css-scale: 0.510; } }
  @media (min-width: 1010px) { html:not(.dw-scaled) { --dw-css-scale: 0.526; } }
  @media (min-width: 1040px) { html:not(.dw-scaled) { --dw-css-scale: 0.541; } }
  @media (min-width: 1070px) { html:not(.dw-scaled) { --dw-css-scale: 0.557; } }
  @media (min-width: 1100px) { html:not(.dw-scaled) { --dw-css-scale: 0.572; } }
  @media (min-width: 1130px) { html:not(.dw-scaled) { --dw-css-scale: 0.588; } }
  @media (min-width: 1160px) { html:not(.dw-scaled) { --dw-css-scale: 0.604; } }
  @media (min-width: 1190px) { html:not(.dw-scaled) { --dw-css-scale: 0.619; } }
  @media (min-width: 1220px) { html:not(.dw-scaled) { --dw-css-scale: 0.635; } }
  @media (min-width: 1250px) { html:not(.dw-scaled) { --dw-css-scale: 0.651; } }
  @media (min-width: 1280px) { html:not(.dw-scaled) { --dw-css-scale: 0.666; } }
  @media (min-width: 1310px) { html:not(.dw-scaled) { --dw-css-scale: 0.682; } }
  @media (min-width: 1340px) { html:not(.dw-scaled) { --dw-css-scale: 0.697; } }
  @media (min-width: 1370px) { html:not(.dw-scaled) { --dw-css-scale: 0.713; } }
  @media (min-width: 1400px) { html:not(.dw-scaled) { --dw-css-scale: 0.729; } }
  @media (min-width: 1430px) { html:not(.dw-scaled) { --dw-css-scale: 0.744; } }
  @media (min-width: 1460px) { html:not(.dw-scaled) { --dw-css-scale: 0.760; } }
  @media (min-width: 1490px) { html:not(.dw-scaled) { --dw-css-scale: 0.776; } }
  @media (min-width: 1520px) { html:not(.dw-scaled) { --dw-css-scale: 0.791; } }
  @media (min-width: 1550px) { html:not(.dw-scaled) { --dw-css-scale: 0.807; } }
  @media (min-width: 1580px) { html:not(.dw-scaled) { --dw-css-scale: 0.822; } }
  @media (min-width: 1610px) { html:not(.dw-scaled) { --dw-css-scale: 0.838; } }
  @media (min-width: 1640px) { html:not(.dw-scaled) { --dw-css-scale: 0.854; } }
  @media (min-width: 1670px) { html:not(.dw-scaled) { --dw-css-scale: 0.869; } }
  @media (min-width: 1700px) { html:not(.dw-scaled) { --dw-css-scale: 0.885; } }
  @media (min-width: 1730px) { html:not(.dw-scaled) { --dw-css-scale: 0.901; } }
  @media (min-width: 1760px) { html:not(.dw-scaled) { --dw-css-scale: 0.916; } }
  @media (min-width: 1790px) { html:not(.dw-scaled) { --dw-css-scale: 0.932; } }
  @media (min-width: 1820px) { html:not(.dw-scaled) { --dw-css-scale: 0.947; } }
  @media (min-width: 1850px) { html:not(.dw-scaled) { --dw-css-scale: 0.963; } }
  @media (min-width: 1880px) { html:not(.dw-scaled) { --dw-css-scale: 0.979; } }
  @media (min-width: 1910px) { html:not(.dw-scaled) { --dw-css-scale: 0.994; } }
  @media (min-width: 1940px) { html:not(.dw-scaled) { --dw-css-scale: 1.010; } }
  @media (min-width: 1970px) { html:not(.dw-scaled) { --dw-css-scale: 1.026; } }
  @media (min-width: 2000px) { html:not(.dw-scaled) { --dw-css-scale: 1.041; } }
  @media (min-width: 2030px) { html:not(.dw-scaled) { --dw-css-scale: 1.057; } }
  @media (min-width: 2060px) { html:not(.dw-scaled) { --dw-css-scale: 1.072; } }
  @media (min-width: 2090px) { html:not(.dw-scaled) { --dw-css-scale: 1.088; } }
  @media (min-width: 2120px) { html:not(.dw-scaled) { --dw-css-scale: 1.104; } }
  @media (min-width: 2150px) { html:not(.dw-scaled) { --dw-css-scale: 1.119; } }
  @media (min-width: 2180px) { html:not(.dw-scaled) { --dw-css-scale: 1.135; } }
  @media (min-width: 2210px) { html:not(.dw-scaled) { --dw-css-scale: 1.151; } }
  @media (min-width: 2240px) { html:not(.dw-scaled) { --dw-css-scale: 1.166; } }
  @media (min-width: 2270px) { html:not(.dw-scaled) { --dw-css-scale: 1.182; } }
  @media (min-width: 2300px) { html:not(.dw-scaled) { --dw-css-scale: 1.197; } }
  @media (min-width: 2330px) { html:not(.dw-scaled) { --dw-css-scale: 1.213; } }
  @media (min-width: 2360px) { html:not(.dw-scaled) { --dw-css-scale: 1.229; } }
  @media (min-width: 2390px) { html:not(.dw-scaled) { --dw-css-scale: 1.244; } }
  @media (min-width: 2420px) { html:not(.dw-scaled) { --dw-css-scale: 1.260; } }
  @media (min-width: 2450px) { html:not(.dw-scaled) { --dw-css-scale: 1.276; } }
  @media (min-width: 2480px) { html:not(.dw-scaled) { --dw-css-scale: 1.291; } }
  @media (min-width: 2510px) { html:not(.dw-scaled) { --dw-css-scale: 1.307; } }
  @media (min-width: 2540px) { html:not(.dw-scaled) { --dw-css-scale: 1.322; } }
  @media (min-width: 2570px) { html:not(.dw-scaled) { --dw-css-scale: 1.338; } }
  @media (min-width: 2600px) { html:not(.dw-scaled) { --dw-css-scale: 1.354; } }
}

/* The score plate is a fixed 76px sized for the widest count, and the frame
   left-aligns inside it after a 13.46px indent. With a single-digit numerator
   that leaves about 22px dead on the right, which reads as a mistake rather
   than as spacing. Centring keeps the plate exactly where it is and shares the
   slack, so it looks deliberate at every count width. */
.row__score {
  justify-content: center;
  padding-left: 0;
}

/* Empty leaderboard. Uses the same dog sticker the out-of-month cells use, so an
   empty year looks like part of the design rather than a missing table. */
.rows--empty { overflow: hidden; }
.dw-nodata {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-align: center;
}
.dw-nodata__art {
  display: block;
  width: 132px;
  height: 132px;
  margin-bottom: 14px;
  opacity: 0.55;
  transform: rotate(-4.44deg);
}
.dw-nodata__art img { width: 100%; height: 100%; display: block; }
.dw-nodata__title {
  margin: 0;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 34px;
  line-height: normal;
  text-transform: lowercase;
  color: rgba(255, 255, 255, 0.85);
  text-box: trim-both cap alphabetic;
}
.dw-nodata__hint {
  margin: 0;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 400;
  font-size: 16px;
  line-height: normal;
  color: rgba(255, 255, 255, 0.45);
}

/* --------------------------------------------------------------------------
   Page fade, independent of view transitions

   Cross-document view transitions are the nice path, but they are silently
   unavailable in plenty of real setups - an unsupporting build, an extension,
   or the OS reduce-motion switch - and then a navigation is a hard cut: the
   interface vanishes and the next one appears. This is the floor under that:
   an explicit fade out on the way off a page and in on the way onto the next
   one, which needs nothing but CSS animation support.

   Gated on .dw-js so a page with no scripting is never left faded, and skipped
   on the first arrival, which has its own choreography behind the skeleton.

   The fade briefly makes .stage a backdrop root, so the frosted panels flatten
   while it runs. At 220ms against a cut that is the better trade.
   -------------------------------------------------------------------------- */
/* No fade IN. Animating opacity on .stage makes it a backdrop root, so .panel,
   the pills and the filter tabs lose their backdrop-filter for the duration and
   render flat - which is the "the blur is missing for a second and then appears"
   this was reported with, and it is also why the stickers looked like they
   arrived ahead of everything else: their images finished decoding at different
   points inside that fade.

   Only the outgoing page fades. On the way out a flat panel for 150ms is not
   something anyone sees, and it keeps a navigation from being a hard cut. */
html.dw-leaving .stage {
  opacity: 0;
  transition: opacity 150ms var(--dw-ease-in, ease-in);
}

/* Reduce motion means no fades, but a navigation must not be left mid-fade */
@media (prefers-reduced-motion: reduce) {
  html.dw-leaving .stage { opacity: 1; transition: none; }
}

/* --------------------------------------------------------------------------
   The three flow-layout blocks on the month screen. They carry no geometry on
   the canvas: the day cell there already shows the roster, the note and the
   count, so the card, the strip and the toggle stay out of the way entirely.
   -------------------------------------------------------------------------- */
.dayview,
.daystrip,
.month-toggle,
.month-actions { display: none; }
/* Alpine fills them with x-text; do not flash empty boxes before it boots */
[x-cloak] .dayview,
[x-cloak] .daystrip,
[x-cloak] .month-toggle,
[x-cloak] .month-actions { display: none !important; }

/* --------------------------------------------------------------------------
   Back to today, canvas side. A third .topbar item, so it lines up with the
   red badge without touching the .header-side column. Only rendered while a
   month other than the current one is open, so the reference frame - whose
   month is the current one - is unaffected. Same fill and blur as .nav-btn.
   -------------------------------------------------------------------------- */
.header-today {
  flex: none;
  align-self: flex-start;
  height: 35px;
  padding: 2px 17px 0;
  border-radius: 9999px;
  border: 1px solid var(--hairline);
  background: var(--pill-fill);
  backdrop-filter: blur(48.75px);
  -webkit-backdrop-filter: blur(48.75px);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 900;
  font-size: 14px;
  line-height: normal;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.header-today:hover { border-color: var(--red); color: #fff; }

/* ==========================================================================
   MOBILE / FLOW LAYOUT

   Everything above is a fixed 1920×1080 canvas: every element absolutely
   positioned in px, the whole thing fitted with one transform: scale(). That
   model dies on a phone. At 390×844 the scale is min(390/1920, 844/1080) =
   0.203, so 12px body text renders at 2.4px. No amount of fitting helps.

   So below a threshold the canvas is abandoned and the same DOM is laid out in
   normal flow. The DOM order inside .stage already reads correctly top to
   bottom - title, nav, panel, stickers - so nothing moves in Blade; the
   absolute positioning is simply undone here.

   Threshold: the canvas stays legible while the scale holds around 0.62, which
   needs width >= 1190 AND height >= 670. The query below is the negation of
   that, so phones in both orientations, tablets, and short desktop windows all
   get the flow layout.

   The same query string is in the inline scaling script in
   resources/views/layouts/app.blade.php - it has to be checked there too,
   because that script sets the transform inline with !important and would
   outrank anything here. Keep the two identical.

   Constraint that shapes this whole block: .nav-btn, .pill, .nav-divider,
   .panel, .ftab--active and .modal__scrim carry backdrop-filter, and animating
   or compositing any ANCESTOR of those flattens the frosted fill. Geometry is
   fair game here; animation is not.
   ========================================================================== */

@media (max-width: 1189px), (max-height: 669px) {

  /* ---------------------------------------------------------------- frame */
  html, body {
    height: auto;
    min-height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    -webkit-text-size-adjust: 100%;
  }
  /* dvh, not vh: the vh unit measures the viewport without the mobile
     address bar, so the page ends up taller than the screen on Safari */
  /* A column so a short page (the month grid is barely half a phone screen)
     can push the ESQRD note to the bottom instead of leaving it stranded in
     the middle of the room photo. dvh, not vh: Safari's address bar. */
  .viewport {
    display: flex;
    flex-direction: column;
    /* The desktop rule centres on both axes to letterbox the canvas. Centring
       the cross axis here would shrink-wrap .stage to its max-content width
       (940px for the leaderboard) instead of the screen width. */
    align-items: stretch;
    justify-content: flex-start;
    width: auto;
    height: auto;
    min-height: 100dvh;
    overflow: visible;
  }
  /* A column, so the ESQRD note can be pushed to the bottom of a short page.
     Width is 100%, not auto: an auto cross-axis margin on a flex item cancels
     the stretch, and the stage would shrink-wrap to its max-content width
     (~940px for a leaderboard row) and hang off the screen. With an explicit
     width the auto margins only do what they are here for - centring the
     column once the viewport is wider than 980px. */
  .stage {
    position: static;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    height: auto;
    max-width: 980px;
    margin: 0 auto;
    padding: 14px 14px 26px;
    transform: none;
  }
  /* The stage is a flex column now, so every child is a flex item and would
     shrink if the column were ever squeezed. Blocks do not shrink; keep it. */
  .stage > * { flex: 0 0 auto; }

  /* ----------------------------------------------------------- header row */
  .topbar {
    position: static;
    left: auto;
    top: auto;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin-bottom: 12px;
  }
  .screen-title { font-size: clamp(32px, 12vw, 58px); }
  .header-side { flex-direction: row; align-items: center; gap: 8px; }
  .header-badge { height: 30px; font-size: 14px; padding: 2px 13px 0 12px; }
  /* The badge is a link on both screens - today's month from the overview, the
     year from a month - and 30px is not a finger. The pseudo-element grows the
     hit area into the slack around it without moving a pixel; [href] keeps it
     off the plain <div> variant. */
  .header-badge[href] { position: relative; }
  .header-badge[href]::after {
    content: '';
    position: absolute;
    inset: -8px -4px;
  }

  /* --------------------------------------------------------------- topnav
     A scroll row rather than a wrap: the pills stay one line and keep their
     46px height, which is also the tap target. */
  .topnav {
    position: static;
    top: auto;
    right: auto;
    gap: 8px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    padding-bottom: 4px;
    margin-bottom: 12px;
    scroll-snap-type: x proximity;
  }
  .topnav::-webkit-scrollbar { display: none; }

  /* On a 390px phone the guest row measures 149 + 155 + 46 plus gaps and the
     last pill lands just past the edge. Trimming the pill padding and dropping
     the purely decorative divider brings it back inside, so the row reads whole
     instead of relying on a scroll the user cannot see. The scroll above stays
     as a safety net for longer translations. */
  .pill { flex: none; padding: 10px 16px; scroll-snap-align: start; }
  .pill__label { font-size: 14px; }
  /* The icon-only pill is a fixed 46px circle, so it must keep the base 10px
     padding - the wider padding above left a 14px content box for a 24px icon
     and shoved the glyph off to the right. justify-content is belt and braces
     against the same thing happening from any later rule. */
  .pill--icon-only {
    padding: 10px;
    justify-content: center;
  }
  /* admin-panel-settings is a dense glyph: shield, notch and person badge. At
     24px the negative space between them closes up and it reads as a blob, so
     it gets the 2px the 46px circle can spare. */
  .pill--icon-only .pill__icon { width: 26px; height: 26px; }

  @media (max-width: 559px) {
    .topnav { gap: 7px; }
    .nav-divider { display: none; }
    .pill { padding: 10px 14px; gap: 8px; }
    .pill__label { font-size: 15px; }
    .pill--icon-only { padding: 10px; }
  }

  /* ---------------------------------------------------------------- panel */
  .panel {
    position: static;
    left: auto;
    top: auto;
    width: auto;
    height: auto;
    padding: 16px;
    border-radius: 22px;
  }
  .panel--strong { height: auto; }
  .panel::before { border-radius: 22px; }
  .panel__inset {
    left: 7px;
    top: 7px;
    right: 7px;
    bottom: 7px;
    width: auto;
    height: auto;
    transform: none;
    border-radius: 16px;
  }
  /* The dot mask is cut to the desktop grid gutters, so it lands nowhere near
     the mobile grid. Plain texture instead - the cards are opaque, so the dots
     still only read in the gaps. */
  .panel__dots--overview,
  .panel__dots--calendar {
    -webkit-mask: none;
    mask: none;
    border-radius: 21px;
  }

  /* -------------------------------------------------------------- overview */
  .ov-heading {
    position: static;
    left: auto;
    top: auto;
    font-size: 20px;
    white-space: normal;
    margin-bottom: 14px;
  }
  .stat {
    position: static;
    left: auto;
    top: auto;
    width: auto;
    height: auto;
    min-height: 44px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px;
    border-radius: 12px;
    margin-bottom: 8px;
  }
  .stat__value {
    position: static;
    left: auto;
    top: auto;
    width: auto;
    min-width: 46px;
    height: 34px;
    padding: 5px 10px 0;
    flex: none;
  }
  .stat__label {
    position: static;
    left: auto;
    top: auto;
    transform: none;
    font-size: 15px;
  }

  .month-grid {
    position: static;
    left: auto;
    top: auto;
    width: auto;
    height: auto;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto;
    gap: 8px;
    margin-top: 14px;
  }
  /* The frame pins the day count to the bottom of a 220x126 card, and the void
     between reads as breathing room at that size. Shrunk to 161x92 the same
     void reads as a mistake, so the card packs its content instead. */
  .mcard {
    display: flex;
    flex-direction: column;
    gap: 7px;
    min-height: 0;
    padding: 11px 11px 12px;
  }
  .mcard__name { position: static; left: auto; top: auto; font-size: 17px; }
  .mcard__days,
  .mcard__marks {
    position: static;
    left: auto;
    right: auto;
    top: auto;
    font-size: 12px;
  }
  .mcard__badge {
    position: static;
    top: auto;
    right: auto;
    align-self: flex-start;
    margin-top: 1px;
  }
  /* .shape is a clip-path generated for exactly 220×126 and falls apart at any
     other size, so the current month gets a plain red outline instead. */
  .mcard--current .shape { display: none; }
  .mcard--current { background: var(--sticker-fill); }
  .mcard--current::before {
    display: block;
    border: 2px solid var(--red);
    background: none;
  }
  .mcard__pin {
    left: auto;
    right: 2px;
    top: -8px;
    width: 34px;
    height: 32px;
  }

  /* Decor competes with data on a small screen: the rocket is 894px and the mug
     and pen sit in the corners the content now occupies. The ESQRD note stays as
     a signature at the end of the page. */
  .rocket { display: none; }
  .sticker--coffee,
  .sticker--pen { display: none; }

  .brand-note {
    position: relative;
    left: auto;
    top: auto;
    width: 132px;
    height: 134px;
    /* auto top margin inside the .stage column: sits just after the content on
       a long page, drops to the bottom edge on a short one */
    margin: auto auto 0;
    padding-top: 18px;
    box-sizing: content-box;
  }
  /* Offsets preserved from the frame: paper 1712.2/987.2, kicker 1732.5/1024.8,
     title 1740.6/1034.0 - the deltas are what keeps the wording on the paper. */
  .brand-note__paper  { left: 0;    top: 0;    }
  .brand-note__kicker { left: 20px; top: 38px; }
  .brand-note__title  { left: 28px; top: 47px; }

  /* ------------------------------------------------------------ month grid
     Seven columns kept, cells reduced to what reads at this size: the number,
     the weekday dot and the marked state. Participants, the series name and the
     comment move into the day modal, which already shows all three. */
  .cal-grid {
    position: static;
    inset: auto;
    padding: 0;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    grid-template-rows: auto;
    gap: 3px;
  }
  .wday {
    height: 28px;
    border-radius: 6px;
    font-size: 11px;
    padding-top: 4px;
  }
  /* Full name out, short name in from the attribute - no extra element, so the
     desktop chip is untouched */
  .wday > span { display: none; }
  .wday::after { content: attr(data-short); }

  .day,
  .day--blank { min-height: 46px; border-radius: 6px; }
  .day::before,
  .day--blank::before { border-radius: 6px; border-width: 2px; }
  .day__head { position: static; left: auto; top: auto; padding: 5px 0 0 5px; }
  .day__num { font-size: 15px; }
  .day__dot { width: 9px; height: 9px; }
  .blank__rot { display: none; }

  .day__people,
  .avatars,
  .day__note,
  .day__fire,
  .day__pin,
  .day__today-badge,
  .day__check { display: none; }

  /* Marked days have to read at a glance - that is what the screen is for.
     The design says it with avatars and a check, and neither fits a 46px cell,
     so a marked day gets a green tick badge instead. .day::before is the border
     overlay, ::after is free. */
  .day--done::after,
  .day--today.day--done::after {
    content: '';
    position: absolute;
    right: 3px;
    bottom: 3px;
    width: 13px;
    height: 13px;
    border-radius: 9999px;
    background: var(--check) center / 9px 9px no-repeat
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5l3.5 3.5 7.5-7.5' fill='none' stroke='%23e2e9d0' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.45);
    pointer-events: none;
  }
  /* and a firmer tint under it, since the design's wash is too faint this small */
  .day--done {
    background:
      linear-gradient(0deg, rgba(30, 164, 27, 0.14), rgba(30, 164, 27, 0.14)),
      linear-gradient(0deg, var(--paper), var(--paper));
  }

  .day--today .shape { display: none; }
  .day--today { background: var(--sticker-fill); }
  .day--today::before {
    display: block;
    border: 2px solid var(--red);
    border-radius: 6px;
  }

  /* ---------------------------------------------------------------- summary
     Four columns do not fit, so a row becomes a two-line card: place, face and
     name on the first line, score and progress on the second. The medals and
     the dense ranking are untouched - only the arrangement changes. */
  .filter-tabs {
    position: static;
    left: auto;
    top: auto;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    padding-bottom: 6px;
    margin-bottom: 12px;
  }
  .filter-tabs::-webkit-scrollbar { display: none; }
  .ftab {
    flex: none;
    height: 40px;
    padding: 8px 14px;
    font-size: 14px;
  }
  .ftab--all { padding: 8px 15px; }
  .ftab .pill__indicator { top: 36px; width: 44px; }

  /* They label a table that no longer has columns */
  .res-head { display: none; }

  .rows {
    position: static;
    left: auto;
    top: auto;
    width: auto;
    height: auto;
    overflow: visible;
    padding-right: 0;
    gap: 8px;
  }
  .row {
    height: auto;
    padding: 10px 12px;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "lead person score"
      "bar  bar    bar";
    align-items: center;
    gap: 8px 10px;
    border-radius: 14px;
  }
  .row__medal {
    position: static;
    left: auto;
    top: auto;
    grid-area: lead;
    width: 42px;
    height: 48px;
    overflow: hidden;
  }
  .row__medal span { transform: rotate(-11.85deg) scale(0.6); }
  /* The thumbs-up overlaps the medal at this size and the gold already says
     first place */
  .row__thumb { display: none; }
  .row__rank {
    position: static;
    left: auto;
    top: auto;
    grid-area: lead;
    width: 42px;
    text-align: center;
    font-size: 22px;
  }
  .row__person {
    position: static;
    left: auto;
    top: auto;
    grid-area: person;
    gap: 8px;
    min-width: 0;
  }
  .row__person img,
  .row__person .ava {
    width: 34px;
    height: 34px;
    border-radius: 8px;
    font-size: 13px;
  }
  /* Two lines rather than an ellipsis: the desktop row shows the whole name and
     nothing else on this screen would give it back, so a long name wraps.
     :not(.ava) matters - the initials avatar is a span in the same row, and
     line-clamping it cuts the letters in half. */
  .row__person > span:not(.ava) {
    font-size: 14px;
    min-width: 0;
    white-space: normal;
    line-height: 1.15;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }
  .row__score {
    position: static;
    left: auto;
    top: auto;
    grid-area: score;
    width: auto;
    min-width: 58px;
    height: 28px;
    padding: 4px 10px 0;
    font-size: 15px;
  }
  /* relative, not static: .row__fill and .row__pct are absolute inside it, and
     with a static track they anchor to .row instead - which put the fill across
     the top of the whole card */
  .row__progress {
    position: relative;
    left: auto;
    top: auto;
    grid-area: bar;
    width: auto;
    height: 24px;
  }
  /* The fill gets its width inline in px, sized against the desktop track of
     615px, which overflows a narrow bar. --dw-pct carries the same number as a
     percentage; !important is needed because an inline style outranks a
     stylesheet otherwise. */
  .row__fill {
    width: calc(var(--dw-pct, 0) * 1%) !important;
    max-width: calc(100% - 6px);
    height: 18px;
  }
  /* The label lives inside .row__progress, not in .row, so it cannot be moved
     to a grid cell. The desktop track is 621px wide and the label only meets
     the fill past 97%; at mobile width they collide from about 80% and the
     number gets eaten.

     So the track becomes a flex row, the label an ordinary item pinned right,
     and z-index puts it over the absolutely positioned fill. The dark chip
     behind it keeps it readable whether it sits on the fill or on the track -
     which is knowable only at render time, not from the server. */
  .row__progress {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: 5px;
  }
  .row__pct {
    position: relative;
    z-index: 1;
    right: auto;
    top: auto;
    transform: none;
    padding: 1px 6px 0;
    border-radius: 6px;
    /* solid, not translucent: 55% black over the orange fill reads as mud */
    background: rgba(12, 9, 8, 0.86);
    color: #fff;
    font-size: 12px;
  }

  .rows--empty { position: relative; min-height: 240px; }
  .dw-nodata { position: static; padding: 34px 0; }
  .dw-nodata__art { width: 92px; height: 92px; margin-bottom: 10px; }
  .dw-nodata__title { font-size: 22px; }
  .dw-nodata__hint { font-size: 13px; padding: 0 10px; }

  /* ----------------------------------------------------------------- modals */
  .modal-root { position: fixed; inset: 0; padding: 12px; }
  .modal__scrim {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    transform: none;
  }
  /* The page must not scroll behind a fixed sheet; boot.js puts the class on
     <html> from the modal root's own hidden attribute. */
  html.dw-modal-open,
  html.dw-modal-open body { overflow: hidden; }

  /* !important: .modal--day sets 760px in the sheet and the login modal sets
     460px inline */
  .modal {
    overscroll-behavior: contain;
    width: 100% !important;
    max-width: 460px;
    max-height: 86dvh;
    overflow-y: auto;
    padding: 20px 18px 18px;
    border-radius: 18px;
  }
  .modal::after { inset: 6px; border-radius: 12px; }
  .modal__title { font-size: 26px; }
  .modal__sub { margin-bottom: 16px; }
  .modal__close { right: 14px; top: 14px; }
  .people-grid { grid-template-columns: 1fr; max-height: 40dvh; }
  .people-tools { flex-wrap: wrap; }
  .people-tools__all { flex: 1 1 auto; }
  .toast { position: fixed; bottom: 16px; }

  /* ---------------------------------------------------------------- skeleton
     The panel skeleton reuses the real containers, so it follows the mobile
     grid on its own. Only the boxes carrying desktop coordinates need undoing,
     and the chrome skeleton goes: there is no fixed title or pill row to cover. */
  .dw-skel--frame { display: none; }
  .dw-skel { padding: 16px; }
  .dw-skel--h1,
  .dw-skel--h2 {
    position: static;
    left: auto;
    top: auto;
    height: 15px;
    margin-bottom: 8px;
  }
  .dw-skel--h1 { width: 72%; }
  .dw-skel--h2 { width: 48%; margin-bottom: 16px; }
  .dw-skel--card { min-height: 92px; }
  .dw-skel--wday { height: 28px; }
  .dw-skel--cell { min-height: 46px; }
  .dw-skel--tab { width: 58px; height: 40px; }
  .dw-skel--tab-all { width: 112px; }
  .dw-skel--head {
    position: static;
    left: auto;
    top: auto;
    width: 100%;
    height: 16px;
    margin: 12px 0;
  }
  .dw-skel__rows {
    position: static;
    left: auto;
    top: auto;
    width: auto;
  }
  .dw-skel--row { height: 64px; border-radius: 14px; }

  /* ------------------------------------------------------------ error pages */
  .err {
    position: static;
    inset: auto;
    padding: 44px 14px;
    min-height: 42vh;
  }
  .err__heading { font-size: 22px; }
  .err__text { font-size: 15px; }
  .err__footer { font-size: 12px; margin-top: 24px; }

  /* ======================================================================
     Second tier: wide phones in landscape and tablets. There is room for the
     participant count, more month columns and the corner check again.
     ====================================================================== */
  @media (min-width: 600px) {
    .month-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .stat { display: inline-flex; width: auto; margin-right: 8px; }
    .day { min-height: 62px; }
    .day--blank { min-height: 62px; }
    .day__people {
      display: flex;
      height: 20px;
      min-width: 0;
      padding: 0 5px;
      margin-top: 0;
    }
    /* 11px matches the desktop badge; 10px was a size the design never uses */
    .day__people span { font-size: 11px; }
    .day__people img { width: 11px; height: 11px; }
    .day__head { gap: 5px; align-items: center; }
    /* The desktop circle is 26px for a mouse. A finger gets 32 - the cell
       itself stays the primary target, this is the shortcut. */
    .day__check {
      display: flex;
      position: absolute;
      left: auto;
      right: 4px;
      bottom: 4px;
      top: auto;
      width: 32px;
      height: 32px;
      border-width: 2px;
    }
    .day__check img { width: 17px; height: 17px; }
    /* The check button is back and turns green when the day is marked, so the
       compact tick badge would sit on top of it saying the same thing twice. */
    .day--done::after,
    .day--today.day--done::after { display: none; }
    .wday { font-size: 13px; height: 30px; }
    .row__person > span:not(.ava) { font-size: 15px; }
  }

  @media (min-width: 768px) {
    .month-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .day { min-height: 82px; }
    .day--blank { min-height: 82px; }
    /* Up to three faces read at this size; more turns into mush */
    .avatars {
      display: flex;
      position: static;
      left: auto;
      top: auto;
      width: auto;
      padding: 0 0 0 5px;
      margin-top: 2px;
    }
    .avatars > *:nth-child(n+4) { display: none; }
    /* 11px is the smallest the design uses, and the plate grows to 24px so
       two initials still clear the 1px border without clipping */
    .avatars img,
    .avatars .ava { width: 24px; height: 24px; font-size: 11px; }
    /* Back to one line, as on the desktop: place, person, score, bar */
    .row { grid-template-columns: auto minmax(0, 1fr) auto auto;
           grid-template-areas: "lead person score bar"; }
    .row__progress { width: 240px; }
  }

  /* Once there is width to spare the bar takes it, the way the 615px desktop
     track does - a 240px bar next to 400px of empty row reads as unfinished. */
  @media (min-width: 900px) {
    .row__progress { width: 360px; }
  }

  /* The rocket earns its place back once there is width to spare. Its internals
     are absolutely sized against a 664px square that is then rotated 62.75deg,
     so the space it needs is 664 * scale * (|cos| + |sin|) = 664 * scale * 1.347.
     At scale .32 that is 286px, which is why the box is 290 and not the 250 that
     looks right on paper - anything smaller cuts the nose off. */
  @media (min-width: 700px) {
    .rocket {
      display: flex;
      position: relative;
      left: auto;
      top: auto;
      width: 100%;
      height: 290px;
      margin-top: 6px;
      overflow: hidden;
    }
    .rocket__rot { transform: rotate(-62.75deg) scale(0.32); }
  }

  /* ==================================================================== */
  /* Day view: what the phone leads with instead of the grid.              */
  /* The 45px cell cannot hold a roster, and nobody opens a popup to find  */
  /* out who marked a day, so the roster is on the screen from the start.  */
  /* ==================================================================== */
  .dayview {
    display: flex;
    flex-direction: column;
    gap: 9px;
    padding: 14px;
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    background: rgba(255, 255, 255, 0.05);
  }
  .dayview__top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
  }
  .dayview__when { min-width: 0; }
  .dayview__date {
    margin: 0;
    font-family: 'Rex', sans-serif;
    font-weight: 700;
    font-size: 30px;
    line-height: normal;
    text-transform: lowercase;
    color: #fff;
    text-box: trim-both cap alphabetic;
  }
  .dayview__wday {
    margin: 5px 0 0;
    font-family: 'PFDinIt', sans-serif;
    font-weight: 400;
    font-size: 13px;
    line-height: normal;
    color: rgba(255, 255, 255, 0.6);
  }
  .dayview__today {
    flex: none;
    height: 24px;
    padding: 1px 10px 0;
    border-radius: 9999px;
    background: var(--red);
    display: flex;
    align-items: center;
    font-family: 'PFDinIt', sans-serif;
    font-weight: 900;
    font-size: 12px;
    line-height: normal;
    text-transform: uppercase;
    color: #fff;
  }
  .dayview__state {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'PFDinIt', sans-serif;
    font-weight: 700;
    font-size: 12px;
    line-height: normal;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.5);
  }
  .dayview__count {
    display: inline-flex;
    align-items: center;
    height: 23px;
    padding: 1px 9px 0;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.09);
    font-size: 14px;
    color: rgba(255, 255, 255, 0.85);
  }
  .dayview__state--on { color: rgba(255, 255, 255, 0.62); }
  .dayview__state--on .dayview__count { background: var(--check); color: #fff; }
  .dayview__count b { font-weight: 900; }
  .dayview__count i { font-style: normal; opacity: 0.75; }
  .dayview__note {
    margin: 0;
    font-family: 'PFDinIt', sans-serif;
    font-style: italic;
    font-weight: 400;
    font-size: 14px;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.82);
  }
  .dayview__people { display: flex; flex-wrap: wrap; gap: 6px; }
  .dvp {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 34px;
    padding: 0 11px 0 4px;
    border-radius: 9999px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.05);
  }
  .dvp img,
  .dvp .ava--dv {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: 9999px;
    border: 1px solid #fff;
    object-fit: cover;
  }
  .ava--dv { font-size: 10px; }
  .dvp__name {
    font-family: 'PFDinIt', sans-serif;
    font-weight: 700;
    font-size: 13px;
    line-height: normal;
    color: rgba(255, 255, 255, 0.85);
    white-space: nowrap;
  }
  .dayview__edit { align-self: flex-start; height: 42px; margin-top: 3px; }

  /* --------------------------------------------------------- day strip --
     Every day of the month in one row that scrolls sideways, each with the
     count on it, so picking a day costs a tap and no day hides its number. */
  .daystrip {
    display: flex;
    gap: 6px;
    margin-top: 12px;
    padding-bottom: 4px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
  }
  .daystrip::-webkit-scrollbar { display: none; }
  .dsd {
    flex: none;
    width: 48px;
    padding: 6px 0 6px;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.09);
    background: rgba(255, 255, 255, 0.04);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    cursor: pointer;
    scroll-snap-align: center;
  }
  .dsd__wd {
    font-family: 'PFDinIt', sans-serif;
    font-weight: 700;
    font-size: 11px;
    line-height: normal;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
  }
  .dsd__num {
    font-family: 'Rex', sans-serif;
    font-weight: 700;
    font-size: 18px;
    line-height: normal;
    color: rgba(255, 255, 255, 0.9);
    text-box: trim-both cap alphabetic;
  }
  /* Reserved whether or not there is a count, so the row does not jitter */
  .dsd__cnt {
    min-width: 18px;
    height: 16px;
    padding: 0 4px;
    border-radius: 9999px;
    font-family: 'PFDinIt', sans-serif;
    font-weight: 900;
    font-size: 11px;
    line-height: 16px;
    color: transparent;
  }
  .dsd--done .dsd__cnt { background: var(--check); color: #fff; }
  .dsd--off .dsd__num { color: rgba(255, 255, 255, 0.45); }
  .dsd--today .dsd__num { color: var(--red); }
  .dsd--sel { border-color: var(--red); background: rgba(254, 58, 58, 0.16); }
  .dsd--sel .dsd__num { color: #fff; }
  .dsd--sel .dsd__wd { color: rgba(255, 255, 255, 0.7); }

  /* ------------------------------------------------------ month toggle --
     The header chip is hidden here: the phone puts both controls in one row
     under the strip, where the thumb already is. */
  .header-today { display: none; }
  .month-actions {
    display: flex;
    gap: 8px;
    margin-top: 10px;
  }
  .month-today {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    height: 42px;
    padding: 0 18px;
    border-radius: 12px;
    border: 1px solid var(--red);
    background: rgba(254, 58, 58, 0.16);
    font-family: 'PFDinIt', sans-serif;
    font-weight: 900;
    font-size: 13px;
    line-height: normal;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: #fff;
    text-decoration: none;
    cursor: pointer;
  }
  .month-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    height: 42px;
    margin-top: 0;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    background: rgba(255, 255, 255, 0.04);
    font-family: 'PFDinIt', sans-serif;
    font-weight: 900;
    font-size: 13px;
    line-height: normal;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.75);
    cursor: pointer;
  }
  .cal-grid { margin-top: 10px; }
  .cal-grid--closed { display: none; }

  /* The month skeleton follows the new shape: one card box, then a strip.
     Reuses the boxes that are already there rather than new markup. */
  .dw-skel .cal-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    grid-template-columns: none;
    grid-template-rows: none;
  }
  .dw-skel--wday { display: none; }
  .dw-skel--wday:first-child {
    display: block;
    width: 100%;
    height: 148px;
    border-radius: 16px;
  }
  .dw-skel--cell { width: 48px; min-height: 62px; flex: none; border-radius: 12px; }
  /* 7 weekday boxes + 8 cells is the whole visible skeleton */
  .dw-skel .cal-grid > .dw-skel--cell:nth-child(n+16) { display: none; }

  @media (max-width: 599px) {
    /* The compact grid is a picker now, and the number of people is the thing
       worth showing there: the count replaces the tick, which said less in the
       same corner. Markup reused - the icon and the "/ 12" tail just go. */
    .day__people {
      display: flex;
      position: absolute;
      left: auto;
      right: 3px;
      bottom: 3px;
      top: auto;
      height: 16px;
      min-width: 16px;
      margin: 0;
      padding: 0 4px;
      border-radius: 9999px;
      border: none;
      background: var(--check);
      align-items: center;
      justify-content: center;
    }
    .day__people img,
    .day__people i { display: none; }
    /* font-size 0 on the wrapper kills the whitespace node left by the tail */
    .day__people > span { font-size: 0; }
    .day__people > span > span {
      font-family: 'PFDinIt', sans-serif;
      font-weight: 900;
      font-size: 10px;
      line-height: 1;
      color: #fff;
    }
    .day--done::after,
    .day--today.day--done::after { display: none; }
  }
}

/* The day's note, read-only for a guest. On desktop it is already in the cell;
   this is what carries it on a phone, where the compact grid drops it. */
.modal__note {
  margin: 0 0 16px;
  font-family: 'PFDinIt', sans-serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.75);
}

/* ── Employee detail modal (summary page, admin only) ───────────────────────── */
.emp-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
}
.emp-modal {
  position: relative;
  background: rgba(20, 30, 40, 0.82);
  backdrop-filter: blur(32px) saturate(1.6);
  -webkit-backdrop-filter: blur(32px) saturate(1.6);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 24px;
  padding: 40px 48px 44px;
  min-width: 360px;
  max-width: 480px;
  text-align: center;
  color: #fff;
}
.emp-modal__close {
  position: absolute;
  top: 16px;
  right: 20px;
  background: none;
  border: none;
  color: rgba(255,255,255,0.5);
  font-size: 20px;
  cursor: pointer;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 8px;
  transition: color .15s, background .15s;
}
.emp-modal__close:hover { color: #fff; background: rgba(255,255,255,0.1); }
.emp-modal__avatar {
  width: 80px;
  height: 80px;
  border-radius: 18px;
  margin: 0 auto 20px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 28px;
}
.emp-modal__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.emp-modal__name {
  margin: 0 0 6px;
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 26px;
  line-height: 1.15;
  text-transform: lowercase;
}
.emp-modal__tg {
  margin: 0 0 28px;
  font-family: 'PFDinIt', sans-serif;
  font-size: 15px;
  color: var(--purple);
  opacity: .85;
}
.emp-modal__stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.emp-modal__stat {
  background: rgba(255,255,255,0.07);
  border-radius: 14px;
  padding: 16px 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.emp-modal__stat-val {
  font-family: 'Rex', sans-serif;
  font-weight: 700;
  font-size: 24px;
  line-height: 1;
}
.emp-modal__stat-label {
  font-family: 'PFDinIt', sans-serif;
  font-size: 12px;
  color: rgba(255,255,255,0.5);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.row--clickable { cursor: pointer; }
.row--clickable:hover { transform: translateX(5px); }
