/* SCF Sale Calendar shell: base, type roles, buttons, inputs, chips, layout, rail, topbar, auth, toasts, dialog, skeleton, mobile, reduced motion.
   Tokens live in tokens.css. Only transform and opacity animate. Curves are --ease and --spring. */

/* 0. The veil behind the confirm dialog, the phone rail sheet and the drawer is --veil in tokens.css, in all
   three theme states. Every rule below keeps its rgba fallback for a browser without custom property support. */

/* 0b. The secondary ink on the accent slab. Contract 13.1 names --accent-ink-2 for it, but at 10.5px to 14px
   that token measures 4.03 to 1 on the powder blue fill and 4.07 to 1 on the dark mirror of it, both under
   the 4.5 bar for text this size. --slab-ink-2 pulls the token 60 percent of the way to --accent-ink, which
   darkens it on the light slab and lifts it on the dark slab from the one expression, and measures 6.57 to 1
   and 5.00 to 1. It is derived from two tokens, so no new colour enters the surface. */
:root { --slab-ink-2: color-mix(in srgb, var(--accent-ink) 60%, var(--accent-ink-2)); }

/* 1. Base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; height: 100%; }
body {
  margin: 0;
  min-height: 100%;
  font: 400 14px/1.5 var(--f-ui);
  color: var(--ink);
  background: var(--linen);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; margin: 0; -webkit-tap-highlight-color: transparent; }
a { color: inherit; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

.ic { width: 16px; height: 16px; flex: none; fill: currentColor; display: inline-block; vertical-align: middle; }

/* A line that may not fit fades out over its last 18px instead of ending in a glyph. The right padding matches the
   fade, so text that fits is never touched; the element carries the full text in its title attribute. */
.fade-clip {
  white-space: nowrap; overflow: hidden; text-overflow: clip; padding-right: 18px;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 18px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 18px), transparent);
}

/* 2. Type roles: each differs from the one above in at least two of font, size, weight, tracking, colour */
.eyebrow { font: 700 11px/1.2 var(--f-ui); letter-spacing: .18em; text-transform: uppercase; color: var(--muted); }
.h { font: 700 22px/1.15 var(--f-display); letter-spacing: -.01em; color: var(--ink); margin: 0; }
.sub { font: 500 14px/1.4 var(--f-ui); color: var(--ink-2); margin: 0; letter-spacing: 0; text-transform: none; }
.copy { font: 400 14px/1.5 var(--f-ui); color: var(--ink-2); margin: 0; letter-spacing: 0; text-transform: none; }
.num { font-variant-numeric: tabular-nums; }

/* 3. Focus, disabled, loading */
:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 2px; }
.rail :focus-visible, .auth-slab :focus-visible { outline-color: var(--accent-ink); }
:disabled, [disabled], .is-disabled { opacity: .45; pointer-events: none; }
.is-loading { animation: pulse 1.2s var(--ease) infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

/* 4. Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 36px; padding: 0 14px;
  border: 1px solid transparent; border-radius: var(--r-md);
  font: 500 14px/1 var(--f-ui); white-space: nowrap; -webkit-user-select: none; user-select: none;
  color: var(--ink); background: transparent;
  transition: transform 120ms var(--ease), opacity 120ms var(--ease);
}
.btn .ic { width: 20px; height: 20px; }
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--ink); color: var(--linen); }
.btn-secondary { border-color: var(--rule-2); color: var(--ink); }
.btn-danger { background: var(--bad); color: var(--linen); }
.btn-ghost { padding: 0 8px; color: var(--ink-2); }
.btn-icon { width: 36px; padding: 0; color: var(--ink-2); }
.btn-sm { height: 30px; padding: 0 10px; font-size: 13px; }
.btn-sm .ic { width: 16px; height: 16px; }
.btn-lg { height: 44px; padding: 0 20px; font-size: 15px; width: 100%; }
.btn.is-loading { pointer-events: none; }

@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { background: var(--ink-2); }
  .btn-secondary:hover { background: var(--linen-2); border-color: var(--rule-2); }
  .btn-danger:hover { background: color-mix(in srgb, var(--bad) 82%, var(--ink)); }
  .btn-ghost:hover, .btn-icon:hover { background: var(--linen-2); color: var(--ink); }
}

/* 5. Inputs: label above, error below. The border steps rule at rest, rule 2 under a fine pointer, ink on focus. */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.field-label { font: 500 13px/1.2 var(--f-ui); color: var(--ink-2); }
.field-wrap { position: relative; }
.input {
  width: 100%; height: 40px; padding: 0 12px;
  border: 1px solid var(--rule); border-radius: var(--r-md);
  background: var(--paper); color: var(--ink);
  font: 400 14px/1.2 var(--f-ui);
  -webkit-appearance: none; appearance: none;
}
.input::placeholder { color: var(--ghost); }
@media (hover: hover) and (pointer: fine) {
  .input:hover { border-color: var(--rule-2); }
}
.input:focus { outline: none; border-color: var(--ink); }
.input:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 1px; }
.field.has-err .input { border-color: var(--bad); }
.field-err { font: 500 12.5px/1.4 var(--f-ui); color: var(--bad); }
.field-err:empty { display: none; }
.field-hint { font-size: 12.5px; color: var(--muted); }
.field-eye { position: absolute; right: 2px; top: 2px; width: 36px; height: 36px; color: var(--muted); }
.field-wrap .input { padding-right: 40px; }
.field-wrap .input:not([type="password"]):not([type="text"]) { padding-right: 12px; }
textarea.input { height: auto; min-height: 88px; padding: 10px 12px; line-height: 1.45; resize: vertical; }
select.input {
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256' fill='%237A7364'%3E%3Cpath d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 16px;
}
/* The caret is a data URI, so it cannot read a token: the dark ground gets the dark ink value drawn in. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) select.input {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256' fill='%23F4ECDC'%3E%3Cpath d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
  }
}
:root[data-theme="dark"] select.input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256' fill='%23F4ECDC'%3E%3Cpath d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
}
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; display: none; }
input[type="date"], input[type="time"] { font-variant-numeric: tabular-nums; }

/* 6. Chips and segmented controls */
.chip {
  --c: var(--u-myer);
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: var(--c); color: var(--linen);
  font: 700 10.5px/1 var(--f-ui); letter-spacing: .04em; text-transform: uppercase;
}
.chip-empty { background: var(--rule); }

.seg { display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--rule); border-radius: var(--r-md); background: var(--linen-2); }
.seg > button {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 12px; border-radius: calc(var(--r-md) - 3px);
  font: 500 13px/1 var(--f-ui); color: var(--muted); white-space: nowrap;
  transition: transform 120ms var(--ease);
}
.seg > button .ic { width: 16px; height: 16px; }
.seg > button[aria-pressed="true"] { background: var(--paper); color: var(--ink); box-shadow: 0 0 0 1px var(--rule); }
.seg > button:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) {
  .seg > button:not([aria-pressed="true"]):hover { color: var(--ink); }
}

/* 6b. Marks the month grid and the board both draw, so they are defined once here and the two views cannot drift:
   the offer pill, the creatives pill and the dot point notes. The channel bubbles are a fixed categorical data
   set of their own and are defined in calendar.css, which loads on every page just as this file does. */
.pill {
  display: inline-flex; align-items: center; gap: 4px; flex: none;
  height: 18px; padding: 0 7px; border-radius: 999px;
  font: 700 11px/1 var(--f-ui); letter-spacing: .01em; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.pill .ic { width: 11px; height: 11px; }
.pill-offer { background: var(--accent-soft); color: var(--accent-strong); }
.pill-files { padding: 0 6px 0 4px; font-weight: 500; background: transparent; color: var(--muted); }
.pill-files.is-full { color: var(--good); }

/* The creatives pill is the calendar's door into the studio, so it has to read as a control rather than a
   label. It is a span, because it sits inside a block that already presents itself as one button. */
.pill-studio { cursor: pointer; box-shadow: inset 0 0 0 1px var(--rule); transition: color .16s var(--ease), background .16s var(--ease), box-shadow .16s var(--ease); }
.pill-studio:hover { color: var(--accent-strong); background: var(--accent-soft); box-shadow: 0 0 0 1px var(--accent); }
.pill-studio:hover .ic { color: var(--accent-strong); }

/* Dot point notes, on two type roles so a cell is scanned rather than read. The two lines that carry a
   figure, the discount and the timing, sit at weight 500 in the full ink with tabular numerals and tighter
   tracking; the two that carry words, the fabrics and the reason, stay at weight 400 in --ink-2. Only the
   first line takes the 3px kind marker the caller passes in as --dp-k, so the kind colour is stated once
   rather than repeated four times under a bar that already carries it; the lines below it indent to match. */
.dps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.dp { display: flex; align-items: flex-start; gap: 6px; overflow-wrap: anywhere; }
.dp-quiet { font: 400 11.5px/1.35 var(--f-ui); letter-spacing: 0; color: var(--ink-2); }
.dp-strong { font: 500 11.5px/1.35 var(--f-ui); letter-spacing: -.008em; color: var(--ink); font-variant-numeric: tabular-nums; }
.dp-lead::before { content: ""; flex: none; width: 3px; height: 3px; margin-top: 6px; border-radius: 999px; background: var(--dp-k, var(--rule-2)); }
.dp:not(.dp-lead) { padding-left: 9px; }
.dp-t { flex: 1; min-width: 0; }
.chip-xs { width: 16px; height: 16px; font-size: 8.5px; letter-spacing: .02em; }

/* 7. Layout: rail fixed left, main to the right with a sticky topbar */
#app { min-height: 100vh; }
#rail {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--rail-w);
  background: var(--accent); color: var(--accent-ink);
  display: flex; flex-direction: column; overflow: visible; z-index: 20;
}
/* A definite height, not a minimum. #view is then a real box with a height of its own, so the month grid
   scroller underneath it has somewhere to scroll however tall the topbar renders. dvh over vh so a browser
   with a collapsing toolbar measures the space the grid actually has. */
#main { margin-left: var(--rail-w); height: 100vh; height: 100dvh; display: flex; flex-direction: column; position: relative; z-index: 1; min-width: 0; }
#topbar {
  position: sticky; top: 0; z-index: 10;
  height: var(--topbar-h); padding: 0 24px;
  display: flex; align-items: center; gap: 16px;
  background: var(--linen); border-bottom: 1px solid var(--rule);
}
/* min-height 0 so the month grid can carry its own scroller as a flex child (contract 13.5) without the
   default auto minimum holding it open. Nothing scrolls here today: the view fills the space and the page grows. */
#view { flex: 1; min-width: 0; min-height: 0; position: relative; }

/* 8. Rail */
.rail-strip, .rail-backdrop, .rail-close { display: none; }
.rail-body { display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: visible; }
.rail-top { flex: none; padding: 24px 24px 20px; overflow: visible; }
.rail-eyebrow { color: var(--slab-ink-2); }
.rail-count {
  font: 800 clamp(120px, 11vw, 168px)/0.85 var(--f-display);
  letter-spacing: -.05em; margin-left: -.05em; margin-right: -12px; margin-top: 10px;
  color: var(--accent-ink); white-space: nowrap; overflow: visible;
  position: relative; z-index: 2;
}
.rail-count.is-word { font-size: clamp(64px, 6vw, 84px); line-height: 1; letter-spacing: -.04em; margin-top: 16px; }
.rail-unit { margin-top: 8px; font: 500 14px/1.2 var(--f-ui); color: var(--slab-ink-2); }
/* The clock under the big number (contract 16.4). The number answers how many days; on the last day a
   number that reads 0 is useless, so this is what carries the urgency. Tabular figures, because a clock
   that shifts sideways every second is unreadable. */
.rail-clock {
  margin-top: 3px;
  font: 600 15px/1.2 var(--f-ui);
  letter-spacing: .06em;
  color: var(--slab-ink-2);
  font-variant-numeric: tabular-nums;
  min-height: 18px;
}
.rail-clock.is-soon { color: var(--slab-ink); font-weight: 700; }
.rail-clock:empty { display: none; }
.rail-title {
  display: block; width: 100%; text-align: left; margin-top: 16px;
  font: 700 18px/1.2 var(--f-display); letter-spacing: -.01em; color: var(--accent-ink);
  border-radius: var(--r-sm);
}
.rail-title:disabled { opacity: 1; pointer-events: none; }
/* The date range is quiet copy; the readiness line above the rule is the figure, heavier and in the cream. */
.rail-range { margin-top: 4px; font: 400 13px/1.4 var(--f-ui); color: var(--slab-ink-2); }
.rail-ready { margin-top: 14px; }
.rail-ready-text { font: 700 12.5px/1.2 var(--f-ui); color: var(--accent-ink); min-height: 15px; }
.rail-rule { height: 2px; margin-top: 8px; border-radius: 1px; overflow: hidden; background: color-mix(in srgb, var(--accent-ink) 18%, transparent); }
.rail-rule-fill { display: block; height: 100%; background: var(--accent-ink); transform-origin: left center; transform: scaleX(0); transition: transform 300ms linear; }
.rail-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 0 24px; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--accent-ink) 40%, transparent) transparent; }
.rail-section { padding: 16px 0; border-top: 1px solid color-mix(in srgb, var(--accent-ink) 18%, transparent); }
.rail-list { list-style: none; margin: 10px 0 0; padding: 0; }
.rail-row {
  display: flex; align-items: center; gap: 10px;
  width: calc(100% + 16px); margin: 0 -8px; padding: 8px;
  text-align: left; border-radius: var(--r-sm); color: var(--accent-ink);
  transition: transform 120ms var(--ease);
}
.rail-row:active { transform: scale(.985); }
.rail-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rail-row-title { font: 500 13.5px/1.25 var(--f-ui); }
.rail-row-date { font: 400 12px/1.2 var(--f-ui); color: var(--slab-ink-2); }
.rail-row-fig { font: 700 12px/1 var(--f-display); color: var(--slab-ink-2); white-space: nowrap; }
.rail-empty { font-size: 13px; color: var(--slab-ink-2); }
.rail-person { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.rail .chip { width: 28px; height: 28px; border: 1.5px solid var(--accent-ink); }
.rail-person-name { flex: 1; min-width: 0; font: 500 13.5px/1.2 var(--f-ui); }
/* A login nobody has claimed yet: the small text colour of the rail, plain weight, so it reads as a note not a name. */
.rail-person-name.is-unclaimed { font-weight: 400; color: var(--slab-ink-2); }
.rail-live { font: 700 10.5px/1 var(--f-ui); letter-spacing: .12em; text-transform: uppercase; color: var(--slab-ink-2); animation: live 2s var(--ease) infinite; }
@keyframes live { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
.rail-foot { flex: none; padding: 16px 24px 20px; display: flex; flex-direction: column; gap: 12px; border-top: 1px solid color-mix(in srgb, var(--accent-ink) 18%, transparent); }
/* Theme toggle and the Team button share one row inside the 224px measure; the row wraps only when a font swap makes it. */
.rail-foot-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 6px; }
/* The tinted ground under the theme buttons sits between the type and the slab and cost another 0.75 of
   contrast ratio, so it drops to a 10 percent tint and the unpressed buttons take the full slab ink:
   7.60 to 1 on the light slab, 4.87 to 1 on the dark one. The pressed button is unchanged at 13.01 to 1. */
.seg-theme { align-self: flex-start; border-color: transparent; background: color-mix(in srgb, var(--accent-ink-2) 10%, transparent); }
.seg-theme > button { height: 26px; padding: 0 7px; font-size: 12px; color: var(--accent-ink); }
.seg-theme > button[aria-pressed="true"] { background: var(--accent-ink); color: var(--accent-soft); box-shadow: none; }
.rail-team-btn { height: 32px; padding: 0 8px; gap: 6px; font-size: 13px; color: var(--slab-ink-2); white-space: nowrap; }
.rail-team-btn .ic { width: 16px; height: 16px; }
.rail-me { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.rail-me-name { font: 700 14px/1.2 var(--f-display); color: var(--accent-ink); min-width: 0; }
.rail-signout { height: 32px; font-size: 13px; color: var(--slab-ink-2); white-space: nowrap; flex: none; }
.rail-signout .ic { width: 16px; height: 16px; }
@media (hover: hover) and (pointer: fine) {
  .rail-row:hover, .rail-title:hover { background: color-mix(in srgb, var(--accent-ink) 12%, transparent); }
  .rail-signout:hover, .rail-team-btn:hover, .rail-menu:hover, .rail-close:hover { background: color-mix(in srgb, var(--accent-ink) 14%, transparent); color: var(--accent-ink); }
  .seg-theme > button:not([aria-pressed="true"]):hover { color: var(--accent-ink); }
}

/* 9. Topbar */
.tb-left { display: flex; align-items: center; gap: 16px; min-width: 0; }
.tb-logo { height: 28px; width: auto; flex: none; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .tb-logo { filter: invert(1) hue-rotate(180deg) brightness(1.1); } }
:root[data-theme="dark"] .tb-logo { filter: invert(1) hue-rotate(180deg) brightness(1.1); }
/* The month is the handle on time: it reads as the heading it is and opens the jump panel, so it carries a
   caret and the pressed and focus states of a control while keeping the heading type role. */
.tb-month { margin: 0; font: 700 22px/1 var(--f-display); letter-spacing: -.01em; white-space: nowrap; }
.tb-month-btn {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0 -8px; padding: 4px 8px; border-radius: var(--r-sm);
  font: inherit; letter-spacing: inherit; color: var(--ink);
  font-variant-numeric: tabular-nums;
  transition: transform 120ms var(--ease);
}
.tb-month-btn:active { transform: scale(.97); }
.tb-month-caret { width: 16px; height: 16px; color: var(--muted); transition: transform 160ms var(--ease); }
.tb-month-btn[aria-expanded="true"] .tb-month-caret { transform: rotate(180deg); color: var(--accent-strong); }
@media (hover: hover) and (pointer: fine) {
  .tb-month-btn:hover { background: var(--linen-2); }
  .tb-month-btn:hover .tb-month-caret { color: var(--ink-2); }
}
.tb-nav { display: flex; align-items: center; gap: 2px; flex: none; }
.tb-left { flex: none; }
.tb-centre { margin: 0 auto; flex: none; }
.tb-right { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex: 1 1 auto; min-width: 0; }
.tb-offline { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border-radius: 999px; background: var(--warn-soft); color: var(--warn); font: 700 11px/1 var(--f-ui); letter-spacing: .08em; text-transform: uppercase; }
.tb-search { position: relative; min-width: 0; flex: 0 1 auto; }
.tb-search-toggle { display: none; }
.tb-search-field { display: flex; align-items: center; position: relative; width: 220px; max-width: 100%; min-width: 0; }
.tb-search-ic { position: absolute; left: 10px; display: flex; color: var(--muted); pointer-events: none; }
.tb-q { height: 36px; padding: 0 32px 0 32px; border-radius: 999px; width: 100%; min-width: 0; }
.tb-search-clear { position: absolute; right: 6px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: var(--muted); }
.tb-search-clear .ic { width: 14px; height: 14px; }
.tb-new .ic { width: 18px; height: 18px; }

/* 10. Auth: the accent slab on the left, the linen form on the right */
body.is-auth { overflow: auto; }
.auth { min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr; }
.auth-slab { background: var(--accent); color: var(--accent-ink); padding: 40px; display: flex; flex-direction: column; justify-content: space-between; gap: 40px; min-height: 100vh; }
.auth-logo { align-self: flex-start; display: inline-flex; padding: 12px 16px; border-radius: var(--r-md); background: var(--accent-soft); }
.auth-logo img { height: 43px; width: auto; }
/* The logo artwork is black, so the plaque stays the light end of the accent: on the dark ground both flip together. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .auth-logo img { filter: invert(1) hue-rotate(180deg) brightness(1.1); } }
:root[data-theme="dark"] .auth-logo img { filter: invert(1) hue-rotate(180deg) brightness(1.1); }
.auth-eyebrow { color: var(--slab-ink-2); }
.auth-date { margin-top: 12px; max-width: 11ch; font: 800 clamp(40px, 4.6vw, 64px)/.95 var(--f-display); letter-spacing: -.03em; color: var(--accent-ink); }
.auth-panel { display: flex; align-items: center; justify-content: center; padding: 40px 24px; background: var(--linen); }
.auth-panel-inner { width: 100%; max-width: 380px; }
.auth-head { margin-bottom: 24px; }
.auth-h { margin-top: 8px; font-size: 32px; }
.auth-sub { margin-top: 8px; }
.auth-submit { margin-top: 8px; }
.auth-form-err { margin: -8px 0 12px; }
.auth-form-err:empty { display: none; margin: 0; }
.auth-swap { display: block; margin: 20px auto 0; padding: 4px 6px; border-radius: var(--r-sm); font: 500 13.5px/1.2 var(--f-ui); color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
@media (hover: hover) and (pointer: fine) { .auth-swap:hover { color: var(--ink); } }

/* 11. Toasts, bottom right */
#toasts { position: fixed; right: 20px; bottom: 20px; z-index: 100; display: flex; flex-direction: column; gap: 8px; max-width: min(440px, calc(100vw - 40px)); pointer-events: none; }
.toast {
  pointer-events: auto; display: flex; align-items: center; gap: 10px;
  padding: 12px 10px 12px 14px; border-radius: var(--r-md);
  background: var(--ink); color: var(--linen);
  font: 500 13.5px/1.35 var(--f-ui);
  opacity: 0; transform: translateY(12px) scale(.97);
  transition: transform 220ms var(--ease), opacity 220ms var(--ease);
}
.toast.is-in { opacity: 1; transform: none; }
.toast.is-out { opacity: 0; transform: translateY(8px) scale(.97); transition-duration: 160ms; }
.toast-ic { display: flex; color: var(--good-soft); }
.toast-bad .toast-ic { color: var(--bad-soft); }
.toast-warn .toast-ic { color: var(--warn-soft); }
.toast-msg { flex: 1; min-width: 0; }
.toast-act { flex: none; padding: 6px 8px; border-radius: var(--r-sm); font: 700 13px/1 var(--f-ui); color: var(--accent-soft); white-space: nowrap; transition: transform 120ms var(--ease); }
.toast-act:active { transform: scale(.97); }
.toast-x { flex: none; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: var(--linen); opacity: .7; }
.toast-x .ic { width: 14px; height: 14px; }
.toast :focus-visible { outline-color: var(--linen); }
@media (hover: hover) and (pointer: fine) {
  .toast-x:hover { opacity: 1; background: color-mix(in srgb, var(--linen) 14%, transparent); }
  .toast-act:hover { background: color-mix(in srgb, var(--linen) 14%, transparent); }
}

/* 12. Confirm dialog, and the Team dialog that shares its frame */
dialog.confirm {
  border: 0; padding: 0; margin: auto;
  width: min(420px, calc(100vw - 32px));
  border-radius: var(--r-lg); background: var(--paper); color: var(--ink);
  opacity: 1; transform: none;
  transition: opacity 160ms var(--ease), transform 160ms var(--ease);
}
dialog.confirm::backdrop { background: rgba(37, 34, 28, .3); background: var(--veil); }
@starting-style { dialog.confirm[open] { opacity: 0; transform: scale(.97); } }
dialog.confirm.is-closing { opacity: 0; transform: scale(.97); }
.confirm-form { padding: 24px; margin: 0; }
.confirm-body { margin-top: 8px; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 24px; }

/* Team: one sheet, sections parted by hairlines. Members, then your password, then for the admin the invite. */
dialog.team-dialog { width: min(560px, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--rule-2) transparent; }
.team-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 24px 24px 16px; }
.team-head .h { margin-top: 4px; }
.team-sec { padding: 20px 24px; border-top: 1px solid var(--rule); }
.team-sec > .eyebrow { margin-bottom: 12px; }
.team-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.team-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--rule); }
.team-row:first-child { border-top: 0; padding-top: 2px; }
.team-row .chip { width: 32px; height: 32px; font-size: 11.5px; }
.team-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.team-row-name { font: 700 14px/1.2 var(--f-display); color: var(--ink); }
.team-row-name.is-unclaimed { font: 400 14px/1.2 var(--f-ui); color: var(--muted); }
.team-row-email { font: 400 12.5px/1.2 var(--f-ui); color: var(--muted); }
.team-row-side { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; text-align: right; }
.team-row-role { font: 700 10.5px/1 var(--f-ui); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.team-row-seen { font: 400 12px/1.2 var(--f-ui); color: var(--ink-2); white-space: nowrap; }
.team-row-seen.is-active { color: var(--good); font-weight: 500; }
.team-row .btn { flex: none; }
.team-form > .eyebrow { margin-bottom: 12px; }
.team-form .field { margin-bottom: 12px; }
.team-form-line { display: flex; align-items: center; gap: 12px; margin-top: 4px; }
.team-form-ok { font: 500 13px/1.3 var(--f-ui); color: var(--good); }
.team-form-ok:empty { display: none; }
.team-form-err { margin-bottom: 8px; }
.team-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
@media (max-width: 479.98px) {
  .team-grid { grid-template-columns: 1fr; }
  .team-row { flex-wrap: wrap; }
  .team-row .btn { margin-left: 44px; }
}

/* 12b. The jump panel: twelve months back to twelve months forward from today, grouped under their year.
   It is a modal dialog for the same reason the confirm and the team sheets are, which is that the platform
   traps focus and answers Escape without a hand written loop, and it is placed under the month heading
   rather than in the middle of the screen so the reader keeps hold of the thing they clicked. */
dialog.jump-dialog {
  position: fixed; inset: auto; margin: 0;
  width: min(340px, calc(100vw - 24px));
  max-height: min(560px, calc(100dvh - 88px));
  overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--ghost) transparent;
}
dialog.jump-dialog::backdrop { background: transparent; }
.jump-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 12px 12px 20px; }
.jump-title { margin: 0; }
.jump-close { width: 30px; height: 30px; color: var(--muted); }
.jump-close .ic { width: 16px; height: 16px; }
.jump-year { padding: 12px 16px 16px; border-top: 1px solid var(--rule); }
/* The year is the display face against the interface face of the eyebrow above it and of the months below it,
   so three type roles sit inside one small panel without reaching for a second colour. */
.jump-year-name { margin: 0 0 10px 4px; font: 700 15px/1 var(--f-display); letter-spacing: -.01em; color: var(--ink); font-variant-numeric: tabular-nums; }
.jump-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.jump-m {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  height: 38px; border-radius: var(--r-sm);
  font: 500 13px/1 var(--f-ui); color: var(--ink-2);
  background: var(--linen-2);
  transition: transform 120ms var(--ease);
}
.jump-m:active { transform: scale(.97); }
/* Today's month keeps a mark of its own so it can be read at the same time as the month being looked at. */
.jump-m-dot { position: absolute; bottom: 6px; left: 50%; width: 4px; height: 4px; margin-left: -2px; border-radius: 999px; background: var(--accent-strong); }
.jump-m.is-on { background: var(--accent); color: var(--accent-ink); font-weight: 700; }
.jump-m.is-on .jump-m-dot { background: var(--accent-ink); }
@media (hover: hover) and (pointer: fine) {
  .jump-m:hover { background: var(--rule); }
  .jump-m.is-on:hover { background: var(--accent-deep); }
}

/* 13. Skeleton blocks: linen 2, no shimmer */
.skel { display: block; background: var(--linen-2); border-radius: var(--r-sm); }

/* 13.9 The middle band, wide enough for the desktop bar and not wide enough for all of it at full size. */
@media (min-width: 1024px) and (max-width: 1399.98px) {
  .tb-search-toggle { display: inline-flex; }
  .tb-search-field { display: none; }
  .tb-search.is-open .tb-search-field {
    display: flex; position: absolute; top: calc(100% + 6px); right: 0;
    width: min(320px, calc(100vw - 24px)); z-index: 5;
  }
  .tb-centre .seg > button > span { display: none; }
  .tb-centre .seg > button { padding-left: 10px; padding-right: 10px; }
}

/* 14. Mobile: rail becomes a top strip, the body opens as a sheet from the left */
@media (max-width: 1023.98px) {
  #rail { top: 0; left: 0; right: 0; bottom: auto; width: auto; height: 56px; flex-direction: row; }
  /* The page scrolls on a phone, so main goes back to a minimum and grows with the agenda under the grid. */
  #main { margin-left: 0; padding-top: 56px; height: auto; min-height: 100vh; min-height: 100dvh; }
  /* The rail is a fixed 56px strip here, so the topbar sticks under it rather than at the viewport top, where
     its first row (the month, Today, the arrows, search and New sale) slid out of sight behind the strip. */
  #topbar { top: 56px; height: auto; min-height: 56px; flex-wrap: wrap; gap: 8px 12px; padding: 8px 12px; }
  .tb-left { gap: 10px 10px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
  .tb-nav { flex: none; }
  .tb-right { flex: none; }
  .tb-logo { height: 22px; }
  .tb-month { font-size: 18px; }
  .tb-centre { order: 3; margin: 0; width: 100%; }
  .tb-centre .seg { display: flex; width: 100%; }
  .tb-centre .seg > button { flex: 1; justify-content: center; }
  .tb-right { gap: 6px; }
  .tb-search-toggle { display: inline-flex; }
  .tb-search-field { display: none; }
  .tb-search.is-open .tb-search-field { display: flex; position: absolute; top: calc(100% + 6px); right: 0; width: min(320px, calc(100vw - 24px)); z-index: 5; }
  .tb-new span { display: none; }
  .tb-new { width: 36px; padding: 0; }
  .tb-new .ic { width: 20px; height: 20px; }
  .tb-offline span { display: none; }
  .tb-offline { padding: 8px; }

  .rail-strip { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; height: 56px; padding: 0 10px 0 16px; }
  .rail-strip-main { display: flex; align-items: baseline; gap: 8px; flex: 1; min-width: 0; text-align: left; color: var(--accent-ink); border-radius: var(--r-sm); }
  .rail-strip-num { font: 800 26px/1 var(--f-display); letter-spacing: -.03em; flex: none; }
  .rail-strip-txt { font: 500 13px/1.2 var(--f-ui); color: var(--slab-ink-2); }
  .rail-menu { display: inline-flex; color: var(--accent-ink); }
  .rail-backdrop { display: block; position: fixed; inset: 0; z-index: 30; background: rgba(37, 34, 28, .3); background: var(--veil); opacity: 0; pointer-events: none; transition: opacity 200ms var(--ease); }
  .rail-body {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 31;
    width: min(calc(var(--rail-w) + 40px), 88vw); height: auto;
    background: var(--accent); overflow: hidden;
    transform: translateX(-100%);
    transition: transform 260ms var(--ease);
  }
  #rail.is-open .rail-backdrop { opacity: 1; pointer-events: auto; }
  #rail.is-open .rail-body { transform: translateX(0); transition-timing-function: var(--ease); }
  .rail-close { display: inline-flex; position: absolute; top: 10px; right: 10px; z-index: 3; color: var(--accent-ink); }
  .rail-top { padding-top: 28px; }
  .rail-count { font-size: clamp(96px, 24vw, 128px); margin-right: 0; }
  .rail-count.is-word { font-size: 64px; }
  body.rail-open { overflow: hidden; }

  /* Toasts leave the bottom of the screen, where the sheet footer (Sign out) and the drawer footer sit, and stack under the strip instead.
     While the sheet is open the whole rail rises above the toast layer so nothing can sit over its buttons. */
  #toasts { top: calc(var(--stick-h, 155px) + 12px); bottom: auto; left: 12px; right: 12px; max-width: none; }
  .toast { transform: translateY(-12px) scale(.97); }
  .toast.is-out { transform: translateY(-8px) scale(.97); }
  #rail.is-open { z-index: 101; }
}

@media (max-width: 799.98px) {
  .auth { grid-template-columns: 1fr; }
  .auth-slab { min-height: 0; padding: 20px 24px; flex-direction: row; align-items: center; gap: 16px; }
  .auth-logo { padding: 8px 10px; }
  .auth-logo img { height: 28px; }
  .auth-date { margin-top: 4px; max-width: none; font-size: 22px; letter-spacing: -.02em; }
  .auth-panel { padding: 32px 20px 48px; }
}

/* 15. Reduced motion: remove travel, keep opacity */
@media (prefers-reduced-motion: reduce) {
  .btn:active, .seg > button:active, .rail-row:active, .toast-act:active { transform: none; }
  .toast { transform: none; transition: opacity 160ms var(--ease); }
  .toast.is-out { transform: none; }
  dialog.confirm { transform: none; transition: opacity 160ms var(--ease); }
  @starting-style { dialog.confirm[open] { transform: none; } }
  dialog.confirm.is-closing { transform: none; }
  .rail-team-btn:active { transform: none; }
  .tb-month-btn:active { transform: none; }
  .tb-month-caret { transition: none; }
  .jump-m:active { transform: none; }
  .rail-rule-fill { transition: none; }
  .is-loading { animation: none; opacity: .7; }
  .rail-live { animation: none; }
  .rail-backdrop { transition: opacity 160ms var(--ease); }
  .rail-body { transition: opacity 200ms var(--ease); }
  #rail.is-open .rail-body { transition: opacity 200ms var(--ease); }
}
@media (prefers-reduced-motion: reduce) and (max-width: 1023.98px) {
  .rail-body { transform: none; opacity: 0; pointer-events: none; }
  #rail.is-open .rail-body { opacity: 1; pointer-events: auto; }
}
