/* ============================================================================================
   kess.css — the KESS self-service portal (App\Custom\Employee\KESS)

   Every class is prefixed `kess-` and every rule scoped under `.kess-root` (the portal) or
   `.kess-portal` (a dialog or borrowed component outside it), so the sheet reaches nothing else.
   The look is the board: bezelled panels on a slate ground, IBM Plex Sans with IBM Plex Mono for
   every figure and every label, blue as the calm accent and amber reserved for attention. Separate
   from kemployee.css because the portal owns a whole document — it has a rail, a topbar and a dark
   theme, none of which a panel inside the ERP frame wants. See `packages/Employee/AGENTS.md`.
   Icons come from kicons.css.
   ========================================================================================= */

/* ---- tokens ----------------------------------------------------------------------------------
   Handed to `.kess-portal` too: a modal has to be a child of <body>, where no `.kess-root` rule
   would reach it. Custom properties paint nothing, so the second selector widens no rule's reach. */
.kess-root,
.kess-portal {

  /* ── the one project token ───────────────────────────────────────────────────────────────────
     The accent is the only colour that changes between installations. Everything accented in the
     portal — the top rule, the brand tile, the active nav entry, the avatar, the calendar button,
     the tab pills, the progress fills, the "see all" links, the annual-leave bars — is mixed from
     this one hex, so an installation sets it once and the whole portal follows.

     `ess_portal.accent_color` on the Ess Portal tab overrides it at runtime: KESSUtil::accentColor()
     writes the chosen hex onto the portal root as this same property, which wins over the value
     below by the cascade. This is the fallback for an installation that has not chosen one.

     Neutrals, status colours and the sidebar's category tiles are fixed and deliberately do NOT
     follow the accent — they carry meaning, and meaning must not change colour per project. */
  --kess-accent-hex:  #707213;

  --kess-bg:          #f1f2f4;
  --kess-surface:     #ffffff;
  --kess-surface-2:   #fafbfc;
  --kess-railbg:      #f7f8fa;
  --kess-sunk:        #eef0f2;
  --kess-border:      #e4e6ea;
  --kess-border-2:    #d6dae0;
  --kess-inner:       #e9ebef;
  --kess-line:        #eef0f2;
  --kess-bezel:       transparent;

  --kess-ink:         #171a1f;
  --kess-ink-2:       #3f4650;
  --kess-ink-soft:    #525862;
  --kess-ink-3:       #5f6672;

  /* The dark solid a primary action is drawn in - a punch-out, a payslip download. */
  --kess-dark:        #171a1f;
  --kess-dark-2:      #2b313b;

  /* Laid over an installation's own hero picture so its type stays readable on either theme. */
  --kess-hero-wash:   rgba(255, 255, 255, .82);

  /* Everything accented, mixed from the one hex above. `-tint` keeps its alpha so it can sit over a
     card or the sidebar without banding; `-wash` and `-line` are flattened onto the surface. */
  --kess-accent:      var(--kess-accent-hex);
  --kess-accent-2:    var(--kess-accent-hex);
  --kess-accent-tint: color-mix(in srgb, var(--kess-accent-hex) 13%, transparent);
  --kess-accent-wash: color-mix(in srgb, var(--kess-accent-hex) 12%, #ffffff);
  --kess-accent-line: color-mix(in srgb, var(--kess-accent-hex) 28%, #ffffff);

  /* Status and category colours. Fixed across installations - see the note on the accent. */
  --kess-primary:     #1d4ed8;  --kess-primary-wash: #e8f1fe;
  --kess-success:     #1f6b45;  --kess-success-wash: #e8f4ee;
  --kess-warning:     #8a5a12;  --kess-warning-wash: #fef3e2;
  --kess-danger:      #a32b21;  --kess-danger-wash:  #fdecea;
  --kess-teal:        #0f5b57;  --kess-teal-wash:    #e4f3f2;
  --kess-indigo:      #4a5fb8;  --kess-indigo-wash:  #e7eaf7;
  --kess-violet:      #5b4b8a;  --kess-violet-wash:  #f3eefe;
  --kess-slate:       #525862;  --kess-slate-wash:   #eef0f2;

  /* Used only where white type sits directly on the colour. All clear 4.5:1. */
  --kess-success-2:   #1a5a3a;
  --kess-warning-2:   #7c500f;
  --kess-danger-2:    #8e251d;
  --kess-teal-2:      #0d4d4a;

  /* A live punch reads as a dot, not a badge, so it needs a colour of its own at full strength. */
  --kess-live:        #1f9d55;
  --kess-live-halo:   rgba(31, 157, 85, .14);

  /* The lit top edge that makes a tinted panel read as glass rather than as flat fill. */
  --kess-glass-hi:    rgba(255, 255, 255, .5);

  /* Leave types, in the order the pattern hands them over. Annual is the commonest, so it takes the
     accent; the rest are fixed hues that stay distinguishable beside any accent a project picks. */
  --kess-leave-1:     var(--kess-accent);
  --kess-leave-2:     #c2703a;
  --kess-leave-3:     #1f6b45;
  --kess-leave-4:     #5b4b8a;
  --kess-leave-5:     #1d4ed8;
  --kess-leave-6:     #0f5b57;

  --kess-r:    6px;
  --kess-r-sm: 5px;
  --kess-r-xs: 4px;
  --kess-r-pill: 3px;

  /* The dashboard's geometry. Kept as its own set rather than moving `--kess-r`, which dresses the
     forms, tables and inputs on every section screen and has no business being card-round. */
  --kess-r-card:  11px;
  --kess-r-md:     9px;
  --kess-r-tile:   7px;
  --kess-r-btn:    6px;
  --kess-r-badge:  4px;
  --kess-r-track: 99px;

  --kess-shadow:  0 1px 2px rgba(16, 22, 29, .05);
  --kess-lift:    0 6px 18px -6px rgba(16, 22, 29, .18), 0 2px 5px -2px rgba(16, 22, 29, .08);
  --kess-ring:    0 0 0 3px color-mix(in srgb, var(--kess-accent-hex) 30%, transparent);
  --kess-pop:     0 12px 32px rgba(23, 26, 31, .14);

  /* The sidebar stands open at the design's 265px and collapses to a strip of icons. Content is laid
     out against the closed width and never reflows, because the open rail floats over it. */
  --kess-rail:      66px;
  --kess-rail-open: 265px;
  --kess-topbar:    56px;
  /* The accent rule across the top of every screen. Everything sticky clears it. */
  --kess-topline:   3px;
  --kess-footer:    34px;
  --kess-aside:     15rem;

  --kess-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: calc(13px * var(--kess-fs-body, 1));
  line-height: 1.55;
  color: var(--kess-ink);
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
}

/* Dark: only the tokens move, so a rule added later cannot forget to handle it. The attribute is
   stamped on <html> by the document and moved by Alpine, where a Livewire morph cannot strip it. */
[data-kess-theme="dark"] .kess-root,
[data-kess-theme="dark"] .kess-portal,
[data-kess-theme="dark"].kess-root,
[data-kess-theme="dark"].kess-portal {

  --kess-bg:          #0c0d0f;
  --kess-surface:     #131417;
  --kess-surface-2:   #17191c;
  --kess-railbg:      #101114;
  --kess-sunk:        #1d1f23;
  --kess-border:      #26292e;
  --kess-border-2:    #343940;
  --kess-inner:       #212429;
  --kess-line:        #212429;
  --kess-bezel:       transparent;

  --kess-ink:         #e8eaec;
  --kess-ink-2:       #b6bcc4;
  --kess-ink-soft:    #9aa1aa;
  --kess-ink-3:       #8b929b;

  /* Inverted: on near-black the dark solid has to be the light one to stay a button. */
  --kess-dark:        #e8eaec;
  --kess-dark-2:      #ffffff;

  --kess-hero-wash:   rgba(12, 13, 15, .84);

  /* The accent hex itself is the installation's and does not move; what moves is how it is mixed.
     Lifted towards white, because a hue chosen to read on white disappears on near-black, and the
     tints are mixed into the surface rather than into paper. */
  --kess-accent:      color-mix(in srgb, var(--kess-accent-hex) 62%, #ffffff);
  --kess-accent-2:    color-mix(in srgb, var(--kess-accent-hex) 48%, #ffffff);
  --kess-accent-tint: color-mix(in srgb, var(--kess-accent-hex) 26%, transparent);
  --kess-accent-wash: color-mix(in srgb, var(--kess-accent-hex) 26%, #131417);
  --kess-accent-line: color-mix(in srgb, var(--kess-accent-hex) 42%, #131417);

  --kess-primary:     #6f9bf0;  --kess-primary-wash: #16203a;
  --kess-success:     #46c08f;  --kess-success-wash: #102a22;
  --kess-warning:     #dd9b3c;  --kess-warning-wash: #2b2113;
  --kess-danger:      #e5736a;  --kess-danger-wash:  #2d1a18;
  --kess-teal:        #3fb5ac;  --kess-teal-wash:    #0f2725;
  --kess-indigo:      #7f90de;  --kess-indigo-wash:  #1a1f33;
  --kess-violet:      #9d88d8;  --kess-violet-wash:  #1f1b30;
  --kess-slate:       #9199a3;  --kess-slate-wash:   #1d2126;

  --kess-success-2:   #2b9270;
  --kess-warning-2:   #b07b28;
  --kess-danger-2:    #c05349;
  --kess-teal-2:      #22867e;

  --kess-live:        #35c274;
  --kess-live-halo:   rgba(53, 194, 116, .18);

  /* Barely there on near-black: a bright edge would read as a seam, not as a highlight. */
  --kess-glass-hi:    rgba(255, 255, 255, .07);

  --kess-leave-1:     var(--kess-accent);
  --kess-leave-2:     #d98a53;
  --kess-leave-3:     #46c08f;
  --kess-leave-4:     #9d88d8;
  --kess-leave-5:     #6f9bf0;
  --kess-leave-6:     #3fb5ac;

  --kess-shadow:  0 1px 2px rgba(0, 0, 0, .4);
  --kess-lift:    0 8px 24px -8px rgba(0, 0, 0, .66), 0 2px 6px -2px rgba(0, 0, 0, .44);
  --kess-pop:     0 12px 32px rgba(0, 0, 0, .55);
  --kess-ring:    0 0 0 3px color-mix(in srgb, var(--kess-accent-hex) 42%, transparent);
  color-scheme: dark;
}

/* ---- reset ---------------------------------------------------------------------------------- */

:is(.kess-root, .kess-portal) *,
:is(.kess-root, .kess-portal) *::before,
:is(.kess-root, .kess-portal) *::after { box-sizing: border-box; }

:is(.kess-root, .kess-portal) a { color: var(--kess-accent-2); text-decoration: none; }
:is(.kess-root, .kess-portal) a:hover { color: var(--kess-accent); text-decoration: none; }

:is(.kess-root, .kess-portal) h1, :is(.kess-root, .kess-portal) h2, :is(.kess-root, .kess-portal) h3,
:is(.kess-root, .kess-portal) h4, :is(.kess-root, .kess-portal) h5, :is(.kess-root, .kess-portal) h6 { margin: 0; font-weight: 600; }

:is(.kess-root, .kess-portal) p { margin: 0 0 8px; }
:is(.kess-root, .kess-portal) p:last-child { margin-bottom: 0; }

:is(.kess-root, .kess-portal) [x-cloak] { display: none !important; }

.kess-root img { max-width: 100%; }
.kess-root { margin: 0; background: var(--kess-bg); min-height: 100vh; }

/* ---- the rail ---------------------------------------------------------------------------------

   A strip of icons, opened and closed by the topbar's toggle. The open state is Alpine's `railOpen`
   on `<body>`, remembered in localStorage, so it survives a navigation — the rail is redrawn on every
   one, and nothing about it is held server-side.

   It pushes the page rather than covering it: the rail is the earlier sibling of the body, so the
   body's margin follows its width on the same curve and the two move as one. `~` rather than `:has()`
   because a sibling combinator is all this needs and every browser has it.

   Below the tablet breakpoint it stops being a rail at all and becomes a drawer that does overlay —
   there is no room to push into, and that part is Alpine's.
*/
.kess-app { display: flex; min-height: 100vh; }

/* A rule of the installation's accent across the full width, above everything. Fixed rather than in
   the flow: the rail and the topbar are both sticky and would slide under a block that scrolled. */
.kess-app::before {
  content: ""; position: fixed; inset: 0 0 auto 0; z-index: 60;
  height: var(--kess-topline); background: var(--kess-accent);
}

.kess-rail {
  position: fixed; inset: var(--kess-topline) auto 0 0; z-index: 40;
  width: var(--kess-rail);
  display: flex; flex-direction: column;
  background: var(--kess-railbg);
  border-right: 1px solid var(--kess-border);
  transition: width .18s cubic-bezier(.4, 0, .2, 1);
  overflow: hidden;
}
.kess-root.is-rail-open .kess-rail { width: var(--kess-rail-open); }

.kess-body {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  margin-left: var(--kess-rail);
  transition: margin-left .18s cubic-bezier(.4, 0, .2, 1);
}
.kess-root.is-rail-open .kess-rail ~ .kess-body { margin-left: var(--kess-rail-open); }

/*
  The keyboard's way in, in rules of its own.

  `:focus-visible`, not `:focus-within`: a mouse click focuses the button it pressed, so a rail opened
  by hovering would stay open after the pointer had left and only close when something else was
  clicked. `:focus-visible` is set for a keyboard focus and not for a click, which is exactly the
  distinction wanted here.

  Separate rules rather than added to the lists above, because a browser that does not understand
  `:has()` drops the entire selector list it appears in — which would take the hover rules with it and
  leave the rail unable to open at all.
*/
.kess-rail:has(:focus-visible) { width: var(--kess-rail-open); }
.kess-rail:has(:focus-visible) ~ .kess-body { margin-left: var(--kess-rail-open); }

.kess-content { flex: 1; min-width: 0; padding: 14px 18px; padding-bottom: calc(26px + var(--kess-footer)); }

/* A section holding a single card centres it. The height is taken from the viewport rather than the
   parent: `.kess-content` is a flex item and a percentage height off it is not reliable. On a phone
   the vertical centring is dropped - a form taller than the screen would be pushed off the top - and
   only the horizontal one is kept. */
.kess-midpane {
  min-height: calc(100vh - var(--kess-topbar) - var(--kess-footer) - 40px);
  display: flex; align-items: center; justify-content: center;
}
@media (max-width: 640px) { .kess-midpane { min-height: 0; } }

/* Fixed, so it is on screen whatever is being read. It starts at the left edge - the login and
   message pages have no rail - and only the portal pushes it across, following the rail on the same
   curve as the body above it. */
.kess-footer {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 25;
  height: var(--kess-footer);
  display: flex; align-items: center; justify-content: center; gap: 4px;
  background: var(--kess-surface);
  border-top: 1px solid var(--kess-border);
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); letter-spacing: .01em; color: var(--kess-ink-3);
  transition: left .18s cubic-bezier(.4, 0, .2, 1);
}
.kess-footer .kess-strong { color: var(--kess-ink-soft); font-weight: 600; }
.kess-body .kess-footer { left: var(--kess-rail); }
.kess-root.is-rail-open .kess-rail ~ .kess-body .kess-footer { left: var(--kess-rail-open); }
.kess-rail:has(:focus-visible) ~ .kess-body .kess-footer { left: var(--kess-rail-open); }

/* Everything that is only there once the rail is open. Held out of the flow by width rather than by
   display, so the row keeps its height and nothing jumps as the labels arrive. */
.kess-rail-wide {
  opacity: 0; min-width: 0;
  transition: opacity .13s ease;
  white-space: nowrap;
}
.kess-root.is-rail-open .kess-rail-wide { opacity: 1; }
.kess-rail:has(:focus-visible) .kess-rail-wide { opacity: 1; }

.kess-root:not(.is-rail-open) .kess-navgroup-title { height: 0; margin: 0; }
.kess-rail:has(:focus-visible) .kess-navgroup-title { height: 15px; margin: 0 0 4px; }

.kess-brand {
  display: flex; align-items: center; gap: 11px;
  height: var(--kess-topbar); flex: none;
  padding: 0 16px 0 21px;
  border-bottom: 1px solid var(--kess-inner);
}
.kess-brand-mark {
  flex: none; width: 26px; height: 26px; border-radius: var(--kess-r-tile);
  display: flex; align-items: center; justify-content: center;
  background: var(--kess-accent-tint); color: var(--kess-accent);
  font-size: 14px; overflow: hidden;
}
.kess-brand-mark > img { width: 100%; height: 100%; object-fit: contain; }
.kess-brand-name {
  font-size: calc(14px * var(--kess-fs-headings, 1)); font-weight: 700; letter-spacing: -.005em; color: var(--kess-ink);
  overflow: hidden; text-overflow: ellipsis;
}

.kess-railscroll { flex: 1; overflow-x: hidden; overflow-y: auto; padding: 9px 9px 14px; scrollbar-width: thin; }
.kess-railscroll::-webkit-scrollbar { width: 6px; }
.kess-railscroll::-webkit-scrollbar-track { background: transparent; }
.kess-railscroll::-webkit-scrollbar-thumb { background: var(--kess-border-2); border-radius: 3px; }

/* Closed, a group is a rule between clusters of icons; open, it is the label it always was. */
.kess-navgroup + .kess-navgroup { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--kess-border); }
.kess-navgroup-title {
  height: 15px; margin: 0 0 4px; padding: 0 10px;
  font-family: var(--kess-mono);
  font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--kess-ink-3);
  overflow: hidden;
}
.kess-root.is-rail-open .kess-navgroup + .kess-navgroup { border-top-color: transparent; }
.kess-rail:has(:focus-visible) .kess-navgroup + .kess-navgroup { border-top-color: transparent; }

.kess-nav-item {
  position: relative;
  display: flex; align-items: center; gap: 11px;
  width: 100%; padding: 7px 12px; margin-bottom: 1px;
  border: 0; background: transparent; text-align: left;
  border-radius: 8px;
  cursor: pointer; user-select: none;
  color: var(--kess-ink-2);
  transition: background .13s ease;
}
.kess-nav-item:hover { background: var(--kess-sunk); }
.kess-nav-item:focus-visible { outline: none; box-shadow: var(--kess-ring); }
.kess-nav-item.is-active { background: var(--kess-accent-tint); }
.kess-nav-item.is-active .kess-nav-title { color: var(--kess-accent); font-weight: 600; }

/* The tile keeps its category colour on the active entry too: the accent says which page you are
   on, the tile says what kind of thing it is, and one must not eat the other. */
.kess-nav-ico {
  flex: none; width: 26px; height: 26px; border-radius: var(--kess-r-tile);
  display: flex; align-items: center; justify-content: center; font-size: 14px;
}
.kess-nav-title {
  font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 500;
  display: flex; align-items: center; gap: 7px; min-width: 0;
}
.kess-nav-title > .kess-ellipsis { flex: 1 1 auto; min-width: 0; }

/* Opening a section is a round trip, so the entry being fetched says so. It takes the accent rather
   than the section's own colour: what is loading is the page, and the icon already says which. */
.kess-nav-spin { flex: none; display: inline-flex; font-size: 13px; color: var(--kess-accent); }

/* A count is worth seeing on a closed rail, so it rides the icon rather than the label. */
.kess-nav-dot {
  position: absolute; top: 4px; left: 28px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--kess-r-pill);
  background: var(--kess-danger-2); color: #fff;
  font-size: 9.5px; font-weight: 700; line-height: 16px; text-align: center;
  box-shadow: 0 0 0 2px var(--kess-surface);
}

.kess-railfoot { flex: none; height: var(--kess-footer); display: flex; align-items: center; padding: 0 9px; }
.kess-railfoot > .kess-nav-item { padding-top: 3px; padding-bottom: 3px; margin-bottom: 0; }
.kess-railfoot .kess-nav-ico { background: var(--kess-accent-tint); color: var(--kess-accent); }
.kess-railfoot .kess-nav-title { color: var(--kess-accent-2); font-weight: 600; }

/* ---- topbar ------------------------------------------------------------------------------------ */

.kess-topbar {
  position: sticky; top: var(--kess-topline); z-index: 30;
  height: var(--kess-topbar); flex: none;
  display: flex; align-items: center; gap: 8px;
  padding: 0 16px;
  background: var(--kess-surface);
  border-bottom: 1px solid var(--kess-border);
}
.kess-topbar-title { font-size: calc(15px * var(--kess-fs-headings, 1)); font-weight: 600; letter-spacing: -.005em; line-height: 1.25; }
.kess-topbar-sub { font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); line-height: 1.3; }

.kess-iconbtn {
  flex: none; width: 31px; height: 31px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--kess-r-tile);
  border: 1px solid transparent; background: transparent;
  color: var(--kess-ink-3); font-size: 15px; cursor: pointer;
  transition: background .13s ease, color .13s ease;
}
.kess-iconbtn:hover { background: var(--kess-sunk); color: var(--kess-ink); }
.kess-iconbtn:focus-visible { outline: none; box-shadow: var(--kess-ring); }
.kess-hamburger { display: none; }
.kess-railbtn { display: flex; }

.kess-me {
  display: flex; align-items: center; gap: 9px;
  padding: 3px 9px 3px 3px; border-radius: var(--kess-r-pill);
  border: 1px solid transparent; background: transparent; cursor: pointer;
  transition: background .13s ease, border-color .13s ease;
}
.kess-me:hover { background: var(--kess-sunk); border-color: var(--kess-border); }
.kess-me-name { font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 600; line-height: 1.25; color: var(--kess-ink); }

/* The initials tile behind a missing photo. Same box as the avatar, so the row never shifts. */
/* A face that cannot break: initials in the box, the photo laid over them, and `onerror` on the image.
   See `inc/face.blade.php` - a photo url that 404s is the common case, not an empty one. */
.kess-facebox {
  position: relative; overflow: hidden; flex: none;
  width: 26px; height: 26px; border-radius: var(--kess-r-tile);
  display: flex; align-items: center; justify-content: center;
  background: var(--kess-accent-tint); color: var(--kess-accent);
  font-family: var(--kess-mono); font-size: 9.5px; font-weight: 600; letter-spacing: .04em;
  box-shadow: 0 0 0 1px var(--kess-border);
}
.kess-facebox > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--kess-sunk); }
.kess-facebox.is-xs { width: 20px; height: 20px; border-radius: 6px; font-size: 8.5px; }
.kess-facebox.is-md { width: 30px; height: 30px; border-radius: 9px; font-size: 10.5px; }
.kess-facebox.is-lg { width: 34px; height: 34px; border-radius: 11px; font-size: 11.5px; }
.kess-facebox.is-hero {
  width: 62px; height: 62px; margin-bottom: 8px; border-radius: 20px; font-size: 19px; letter-spacing: .02em;
  background: var(--kess-surface);
  box-shadow: 0 0 0 1px var(--kess-accent-line), 0 2px 10px rgba(33, 43, 61, .08);
}

/* A 1px rule separating the notifications cluster from who is signed in. */
.kess-topbar-sep { flex: none; width: 1px; height: 26px; margin: 0 2px; background: var(--kess-inner); }

.kess-menu {
  position: absolute; right: 0; top: calc(100% + 7px); z-index: 60;
  min-width: 208px; padding: 6px;
  background: var(--kess-surface);
  border: 1px solid var(--kess-border);
  border-radius: var(--kess-r-md);
  box-shadow: var(--kess-pop);
}
.kess-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 7px 10px;
  border: 0; background: transparent; text-align: left;
  border-radius: var(--kess-r-xs);
  font-size: calc(12.5px * var(--kess-fs-body, 1)); color: var(--kess-ink); cursor: pointer;
}
.kess-menu-item:hover { background: var(--kess-sunk); color: var(--kess-ink); }
.kess-menu-item > .ksty { color: var(--kess-ink-3); font-size: 14px; }
.kess-menu-item.is-danger { color: var(--kess-danger); }
.kess-menu-item.is-danger > .ksty { color: var(--kess-danger); }
.kess-menu-sep { height: 1px; margin: 5px 2px; background: var(--kess-border); }

/* The theme row carries the only control in the portal that moves for its own sake. It earns it:
   this is the one setting that repaints everything you can see, so the switch throwing is worth
   watching. Both glyphs are drawn and crossfaded rather than swapped, so neither one pops. */
.kess-themeglyph { position: relative; flex: none; width: 14px; height: 14px; }
.kess-themeglyph > .ksty {
  position: absolute; inset: 0;
  font-size: 14px; line-height: 14px; color: var(--kess-ink-3);
  transition: opacity .22s ease, transform .3s cubic-bezier(.4, 0, .2, 1);
}
.kess-themeglyph > .ksty-moon { opacity: 0; transform: rotate(-80deg) scale(.55); }
.kess-themeitem.is-on .kess-themeglyph > .ksty-sun { opacity: 0; transform: rotate(80deg) scale(.55); }
.kess-themeitem.is-on .kess-themeglyph > .ksty-moon { opacity: 1; transform: none; }
.kess-themeitem.is-on .kess-themeglyph > .ksty { color: var(--kess-accent); }

.kess-switch {
  position: relative; flex: none; width: 30px; height: 17px;
  border: 1px solid var(--kess-border); border-radius: var(--kess-r-track);
  background: var(--kess-sunk);
  transition: background .22s ease, border-color .22s ease;
}
.kess-themeitem.is-on .kess-switch {
  background: color-mix(in srgb, var(--kess-accent) 30%, transparent);
  border-color: color-mix(in srgb, var(--kess-accent) 48%, transparent);
}
/* The overshoot is the whole point of the knob - it lands like a physical switch. */
.kess-switch-knob {
  position: absolute; top: 2px; left: 2px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--kess-ink-3);
  transition: transform .3s cubic-bezier(.34, 1.42, .48, 1), background .22s ease;
}
.kess-themeitem.is-on .kess-switch-knob { transform: translateX(13px); background: var(--kess-accent); }

/* ---- the shell ----------------------------------------------------------------------------------

   Two columns: whatever is open, and a fixed strip of who this is.

   The strip is sticky because its job is to stay true while you read something else - an employee
   checking a payslip should not have to remember which contract it is against. It is the width of the
   longest thing in it and no wider, so the reading column keeps everything left over.

   `align-self: start` is what lets it stick: the row is as tall as the main column, and the aside's
   own box is only as tall as its content, which is the travel room sticky needs.
*/
.kess-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--kess-aside);
  grid-template-areas: "main rail";
  gap: 14px;
  align-items: start;
}
.kess-main { grid-area: main; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.kess-aside {
  grid-area: rail; min-width: 0;
  position: sticky; align-self: start;
  top: calc(var(--kess-topbar) + 16px);
  max-height: calc(100vh - var(--kess-topbar) - var(--kess-footer) - 32px);
  overflow-y: auto; scrollbar-width: thin;
}
.kess-aside::-webkit-scrollbar { width: 6px; }
.kess-aside::-webkit-scrollbar-track { background: transparent; }
.kess-aside::-webkit-scrollbar-thumb { background: var(--kess-border-2); border-radius: 3px; }

/* Too narrow for two columns: who this is goes above what is open, rather than below it, because it
   is the thing that gives the rest its context. */
.kess-shell.is-wide { grid-template-columns: minmax(0, 1fr); grid-template-areas: "main"; }

@media (max-width: 1180px) {
  .kess-shell { grid-template-columns: minmax(0, 1fr); grid-template-areas: "rail" "main"; }
  .kess-aside { position: static; max-height: none; overflow: visible; }
}

/* ---- who this is ---------------------------------------------------------------------------------- */

.kess-whois {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 18px 14px 14px;
  border-bottom: 1px solid var(--kess-border);
  background: var(--kess-accent-wash);
  text-align: center;
}
.kess-whois-name {
  max-width: 100%;
  font-size: calc(14.5px * var(--kess-fs-headings, 1)); font-weight: 650; letter-spacing: -.015em; color: var(--kess-ink);
}
.kess-whois-id { font-size: calc(11px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }
.kess-whois-foot { padding: 12px 14px; border-top: 1px solid var(--kess-border); }

/* A dot and a word rather than a pill: the standing is a fact about the person, not a chip competing
   with the badges further down the page. */
.kess-standing {
  margin-top: 6px;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: calc(11.5px * var(--kess-fs-secondary, 1)); font-weight: 600; letter-spacing: .01em; color: var(--kess-ink-3);
  white-space: nowrap;
}
.kess-standing::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--kess-ink-3); }
.kess-standing.is-on { color: var(--kess-success); }
.kess-standing.is-on::before { background: var(--kess-success); box-shadow: 0 0 0 3px var(--kess-success-wash); }

/* ---- the hero, and the figures across its foot -----------------------------------------------

   The dashboard opens with one card: whatever the employee does every day (the punch console, where
   the installation has it) over a strip of the figures that describe their month. A strip rather
   than five more cards, because these are a reading of the screen below and not another thing on it,
   and every figure opens the section that explains it - a figure you cannot act on is a decoration.
*/
/* The section's single root, and what puts air between the hero and the deck below it. */
.kess-home { display: flex; flex-direction: column; gap: 16px; }

.kess-hero { display: flex; flex-direction: column; }
.kess-hero-top { padding: 14px 16px 12px; }

.kess-kpistrip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  border-top: 1px solid var(--kess-line);
}
/* Nothing above it - punching is switched off, or this contract has no site to punch against - so
   the strip is the card and opens with no rule. */
.kess-kpistrip.is-lead { border-top: 0; }

.kess-kpi {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 11px 18px; min-width: 0;
  border: 0; border-right: 1px solid var(--kess-line);
  background: transparent; text-align: left; font-family: inherit;
  cursor: pointer; transition: background .13s ease;
}
.kess-kpi:last-child { border-right: 0; }
.kess-kpi:hover { background: var(--kess-surface-2); }
.kess-kpi:focus-visible { outline: none; box-shadow: var(--kess-ring); }

.kess-kpi-label {
  font-family: var(--kess-mono);
  font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  color: var(--kess-ink-3);
}
/* The figure and its unit set on one baseline, so a count reads as a measurement, not a headline. */
.kess-kpi-value {
  display: flex; align-items: baseline; gap: 5px; min-width: 0;
  font-family: var(--kess-mono);
  font-size: calc(20px * var(--kess-fs-figures, 1)); font-weight: 600; line-height: 1; color: var(--kess-ink);
  font-variant-numeric: tabular-nums;
}
.kess-kpi-value.is-tight { font-size: calc(19px * var(--kess-fs-figures, 1)); }
.kess-kpi-unit {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); font-weight: 400; letter-spacing: 0; color: var(--kess-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 720px) {
  .kess-kpistrip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kess-kpi:nth-child(2n) { border-right: 0; }
  .kess-kpi + .kess-kpi + .kess-kpi { border-top: 1px solid var(--kess-line); }
}

/* Kept for the section screens that still set a figure in the old places. */
.kess-figure-value {
  display: inline-flex; align-items: baseline; gap: 4px;
  font-family: var(--kess-mono);
  font-size: calc(22px * var(--kess-fs-figures, 1)); font-weight: 600; letter-spacing: -.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.kess-figure-value > small { font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 500; letter-spacing: 0; color: var(--kess-ink-3); }
.kess-figure-label {
  font-family: var(--kess-mono);
  font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--kess-ink-3);
}
.kess-figure-note { font-size: calc(10.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }

/* ---- surfaces ----------------------------------------------------------------------------------- */

/* Borders, not shadows: a column of shadowed cards on a light canvas reads as a pile of receipts. */
.kess-card {
  background: var(--kess-surface);
  border: 1px solid var(--kess-border);
  border-radius: var(--kess-r-card);
  overflow: hidden;
}
/* A card clips its corners, which would clip a dropdown opened inside a borrowed component. Those
   let their content out instead — nothing in them paints to the edge, so the corners still read. */
.kess-card.kess-guest { overflow: visible; }
.kess-card.kess-guest.kess-clip { overflow: hidden; }

/* No fill, and the title is an eyebrow rather than a heading: on a screen that is a column of cards,
   a filled bar per card is a stripe pattern, and eight bold headings compete with the content. */
.kess-card-head {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 13px;
  background: var(--kess-surface-2);
  border-bottom: 1px solid var(--kess-line);
}
.kess-card-head > .ksty { font-size: 14px; }
.kess-card-head > .ksty:not([class*="kess-ic-"]) { color: var(--kess-ink-3); }
.kess-card-title {
  font-family: var(--kess-mono);
  font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--kess-ink);
}
/* A tabbed card puts pills where the title would be, so the head loses a little of its padding. */
.kess-card-head.is-tabbed { padding: 8px 11px; flex-wrap: wrap; }
.kess-card-tools { margin-left: auto; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.kess-card-body { padding: 12px 13px 13px; }
.kess-card-body.is-flush { padding: 0; }

.kess-stack { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
/* auto-fit rather than a fixed three: the deck falls 3 -> 2 -> 1 on its own, and a column that has
   no cards on this employee's dashboard costs no empty track. */
.kess-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(245px, 1fr)); gap: 12px; align-items: start; }
.kess-grid > .kess-col { min-width: 0; display: flex; flex-direction: column; gap: 12px; }
@media (max-width: 560px) { .kess-grid { grid-template-columns: minmax(0, 1fr); } }

.kess-scroll { overflow-y: auto; scrollbar-width: thin; }
.kess-scroll-md { max-height: 440px; }
.kess-scroll-sm { max-height: 280px; }
.kess-scroll::-webkit-scrollbar { width: 7px; height: 7px; }
.kess-scroll::-webkit-scrollbar-track { background: transparent; }
.kess-scroll::-webkit-scrollbar-thumb { background: var(--kess-border-2); border-radius: 4px; }

/* ---- accents (shared by icon squares, tiles and chips) --------------------------------------- */

.kess-ac-primary { background: var(--kess-primary-wash) !important; color: var(--kess-primary) !important; }
.kess-ac-teal    { background: var(--kess-teal-wash)    !important; color: var(--kess-teal)    !important; }
.kess-ac-slate   { background: var(--kess-slate-wash)   !important; color: var(--kess-slate)   !important; }
.kess-ac-success { background: var(--kess-success-wash) !important; color: var(--kess-success) !important; }
.kess-ac-warning { background: var(--kess-warning-wash) !important; color: var(--kess-warning) !important; }
.kess-ac-danger  { background: var(--kess-danger-wash)  !important; color: var(--kess-danger)  !important; }
.kess-ac-indigo  { background: var(--kess-indigo-wash)  !important; color: var(--kess-indigo)  !important; }
.kess-ac-violet  { background: var(--kess-violet-wash)  !important; color: var(--kess-violet)  !important; }

/* The glyph on a card head takes the card's own accent - the same one its nav entry wears. Nine
   identical white boxes are unscannable; nine tinted markers are read at a glance, and it costs no
   extra geometry. Colour only, no fill: the fills belong to the list rows inside. */
.kess-ic-primary { color: var(--kess-primary); }
.kess-ic-success { color: var(--kess-success); }
.kess-ic-warning { color: var(--kess-warning); }
.kess-ic-danger  { color: var(--kess-danger); }
.kess-ic-teal    { color: var(--kess-teal); }
.kess-ic-indigo  { color: var(--kess-indigo); }
.kess-ic-violet  { color: var(--kess-violet); }
.kess-ic-slate   { color: var(--kess-slate); }

/* a small square holding one icon — list rows, meta rows, tiles */
.kess-sqico {
  flex: none; width: 28px; height: 28px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; font-size: 14px;
  background: var(--kess-slate-wash); color: var(--kess-slate);
}
.kess-sqico.is-lg { width: 34px; height: 34px; border-radius: 11px; font-size: 16px; }
.kess-sqico.is-sm { width: 20px; height: 20px; border-radius: 6px; font-size: 12px; }

/* a person's own photo at the size a name is set in */
.kess-face {
  flex: none; width: 20px; height: 20px; border-radius: 6px;
  object-fit: cover; background: var(--kess-sunk);
  box-shadow: 0 0 0 1px var(--kess-border);
}
.kess-face.is-lg { width: 34px; height: 34px; border-radius: 11px; }

/* ---- badges -------------------------------------------------------------------------------------- */

.kess-badge {
  font-family: var(--kess-mono); text-transform: uppercase; letter-spacing: .08em;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 6px; border-radius: var(--kess-r-badge);
  font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600; line-height: 1;
  background: var(--kess-slate-wash); color: var(--kess-slate);
  border: 1px solid transparent; white-space: nowrap;
}
.kess-badge > .ksty { font-size: 11px; }
/* The count on a card head - a figure, so it keeps a digit's width rather than a word's padding. */
.kess-badge.is-num { padding: 4px 6px; min-width: 19px; justify-content: center; letter-spacing: .02em; }
/* The one badge drawn as a solid: approvals waiting, which is somebody else being held up. */
.kess-badge.is-solid-danger { background: var(--kess-danger); color: #fff; }
.kess-badge.is-success { background: var(--kess-success-wash); color: var(--kess-success); }
.kess-badge.is-danger  { background: var(--kess-danger-wash);  color: var(--kess-danger); }
.kess-badge.is-warning { background: var(--kess-warning-wash); color: var(--kess-warning); }
.kess-badge.is-info,
.kess-badge.is-primary { background: var(--kess-primary-wash); color: var(--kess-primary); }
.kess-badge.is-teal    { background: var(--kess-teal-wash);    color: var(--kess-teal); }
.kess-badge.is-indigo  { background: var(--kess-indigo-wash);  color: var(--kess-indigo); }
.kess-badge.is-violet  { background: var(--kess-violet-wash);  color: var(--kess-violet); }
.kess-badge.is-slate   { background: var(--kess-slate-wash);   color: var(--kess-slate); }
.kess-badge.is-plain   { background: var(--kess-surface); color: var(--kess-ink-soft); border-color: var(--kess-border); }
.kess-badge.is-count   { min-width: 20px; justify-content: center; padding: 2px 7px; }
.kess-badge.kess-mono  { font-size: calc(9px * var(--kess-fs-labels, 1)); letter-spacing: .02em; }
a.kess-badge:hover { filter: brightness(.97); color: inherit; }

/* ---- buttons ------------------------------------------------------------------------------------- */

.kess-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 32px; padding: 0 12px;
  font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 500; font-family: inherit; cursor: pointer;
  border-radius: var(--kess-r-btn); border: 1px solid var(--kess-border);
  background: var(--kess-surface); color: var(--kess-ink-soft);
  transition: background .13s ease, border-color .13s ease, color .13s ease, box-shadow .13s ease;
  white-space: nowrap;
}
.kess-btn:hover { background: var(--kess-sunk); color: var(--kess-ink); border-color: var(--kess-border-2); }
.kess-btn:focus-visible { outline: none; box-shadow: var(--kess-ring); }
.kess-btn:disabled, .kess-btn.is-disabled { opacity: .5; cursor: not-allowed; }
.kess-btn:disabled:hover { background: var(--kess-surface); border-color: var(--kess-border); color: var(--kess-ink-soft); }

/* The dark solid: the one action on a card that is the reason the card is there - punch out, take
   the payslip. Near-black rather than the accent, so it does not compete with the accented links. */
.kess-btn.is-dark { background: var(--kess-dark); border-color: var(--kess-dark); color: var(--kess-bg); font-weight: 600; }
.kess-btn.is-dark:hover { background: var(--kess-dark-2); border-color: var(--kess-dark-2); color: var(--kess-bg); }

/* Primary keeps the light accent — it is the button that appears most. The semantic solids take the
   darker step: they are rare, and a Withdraw is a button you want to be unmistakable. */
.kess-btn.is-primary { background: var(--kess-accent); border-color: var(--kess-accent); color: #fff; }
.kess-btn.is-success { background: var(--kess-success-2); border-color: var(--kess-success-2); color: #fff; }
.kess-btn.is-danger  { background: var(--kess-danger-2);  border-color: var(--kess-danger-2);  color: #fff; }
.kess-btn.is-primary:hover,
.kess-btn.is-success:hover,
.kess-btn.is-danger:hover { filter: brightness(.93); color: #fff; }
.kess-btn.is-soft { background: var(--kess-accent-tint); border-color: transparent; color: var(--kess-accent); }
.kess-btn.is-soft:hover { background: var(--kess-accent-line); border-color: transparent; color: var(--kess-accent); }
.kess-btn.is-ghost { background: transparent; border-color: transparent; color: var(--kess-ink-2); }
.kess-btn.is-ghost:hover { background: var(--kess-sunk); border-color: transparent; color: var(--kess-ink); }
.kess-btn.is-link { border-color: transparent; background: transparent; color: var(--kess-accent-2); height: 28px; padding: 0 7px; }
.kess-btn.is-link:hover { background: var(--kess-accent-wash); border-color: transparent; }
.kess-btn.is-sm { height: 26px; padding: 0 9px; font-size: calc(11px * var(--kess-fs-secondary, 1)); border-radius: var(--kess-r-btn); gap: 5px; }
.kess-btn.is-icon { width: 34px; padding: 0; }
.kess-btn.is-icon.is-sm { width: 26px; }
.kess-btn.is-block { width: 100%; }
:is(.kess-root, .kess-portal) label.kess-btn { margin: 0; }

.kess-btnbar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.kess-btnbar.is-end { justify-content: flex-end; }

/* ---- read-only field pairs ------------------------------------------------------------------------

   A ruled grid, label above value, several to a row where the card is wide enough. A two-column
   label/value list leaves a gutter down the middle of every card and reads as half-empty.
*/
.kess-defs { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); margin-right: -1px; }
.kess-defs.is-stacked { grid-template-columns: minmax(0, 1fr); margin-right: 0; }
.kess-defs.is-stacked > .kess-def { border-right: 0; padding: 9px 14px; }
.kess-def {
  min-width: 0; padding: 11px 16px;
  border-bottom: 1px solid var(--kess-border);
  border-right: 1px solid var(--kess-border);
}
.kess-def-label {
  font-family: var(--kess-mono);
  display: flex; align-items: center; gap: 5px;
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); text-transform: uppercase; letter-spacing: .06em;
  font-weight: 700; color: var(--kess-ink-3);
}
.kess-def-value { margin-top: 1px; font-size: calc(13px * var(--kess-fs-body, 1)); color: var(--kess-ink); word-break: break-word; }
.kess-def-value.is-empty { color: var(--kess-ink-3); font-style: italic; }

/* ---- lists ------------------------------------------------------------------------------------------ */

.kess-list { display: flex; flex-direction: column; }
.kess-list-item {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--kess-border);
}
.kess-list-item:last-child { border-bottom: 0; }
.kess-list-item.is-hoverable:hover { background: var(--kess-surface-2); }
.kess-list-body { min-width: 0; flex: 1 1 auto; }
.kess-list-title {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: calc(13px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink);
}
.kess-list-note { margin-top: 3px; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }
.kess-list-side { flex: none; margin-left: auto; display: flex; align-items: center; gap: 7px; }

/* ---- stat tiles ---------------------------------------------------------------------------------------

   auto-fill, not auto-fit: three tiles keep a tile's width rather than stretching to a third of the card.
*/
.kess-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(184px, 1fr)); gap: 12px; }
.kess-stat {
  background: var(--kess-surface); border: 1px solid var(--kess-border);
  border-radius: var(--kess-r); padding: 13px 14px; box-shadow: var(--kess-shadow);
  transition: box-shadow .16s ease, transform .16s ease;
}
.kess-stat:hover { box-shadow: var(--kess-lift); transform: translateY(-1px); }
.kess-stat-ico {
  width: 30px; height: 30px; border-radius: 9px; margin-bottom: 9px;
  display: flex; align-items: center; justify-content: center; font-size: 15px;
}
.kess-stat-label { font-family: var(--kess-mono); font-size: calc(9.5px * var(--kess-fs-labels, 1)); text-transform: uppercase; letter-spacing: .15em; font-weight: 600; color: var(--kess-ink-3); }
.kess-stat-value {
  font-family: var(--kess-mono);
  margin-top: 2px; font-size: calc(14.5px * var(--kess-fs-figures, 1)); font-weight: 600; letter-spacing: -.01em; color: var(--kess-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kess-stat-value.is-lg { font-size: calc(19px * var(--kess-fs-figures, 1)); letter-spacing: -.02em; }
.kess-stat-note { font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }
/* A tile whose value is a sentence, not a figure - the shift line. Two tracks where there are two to
   give; on one track `span 2` would overflow the grid, so it goes back to one. */
.kess-stat.is-wide { grid-column: span 2; }
@media (max-width: 560px) { .kess-stat.is-wide { grid-column: auto; } }

/* ---- tabs ---------------------------------------------------------------------------------------------- */

.kess-tabs { display: flex; gap: 4px; flex-wrap: wrap; padding: 10px 12px 0; border-bottom: 1px solid var(--kess-border); }
.kess-tab {
  padding: 8px 13px 10px; margin-bottom: -1px;
  border: 0; border-bottom: 2px solid transparent; background: transparent;
  font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 550; color: var(--kess-ink-3); cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  transition: color .13s ease;
}
.kess-tab:hover { color: var(--kess-ink); }
.kess-tab.is-active { color: var(--kess-accent-2); border-bottom-color: var(--kess-accent); }
.kess-tab-count {
  min-width: 17px; padding: 1px 5px;
  border-radius: var(--kess-r-pill); background: var(--kess-sunk);
  font-family: var(--kess-mono); font-size: calc(9.5px * var(--kess-fs-labels, 1)); font-weight: 600;
  color: var(--kess-ink-3); font-variant-numeric: tabular-nums;
}
.kess-tab.is-active .kess-tab-count { background: var(--kess-accent-wash); color: var(--kess-accent-2); }

/* A tab strip inside a padded card body has to reach the card's edges to read as a strip. */
.kess-tabs.is-inset { margin: -13px -14px 13px; padding: 9px 14px 0; }
.kess-formtabs { margin: 0 0 14px; padding: 0; }
.kess-tab-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--kess-danger-2); vertical-align: middle; }

/* ---- what the dashboard's cards are made of ---------------------------------------------------
   Twelve cards in one identical frame read as one table repeated twelve times. The frame stays
   uniform - that is what makes a wall of cards legible - and the bodies below carry the difference,
   each shaped like the thing it holds: a queue, a strip of occasions, a dated timeline, a docket of
   files, a stack of tickets. */

.kess-tag {
  display: inline-flex; align-items: center;
  padding: 3px 5px; border-radius: var(--kess-r-badge);
  background: var(--kess-sunk); border: 0;
  font-family: var(--kess-mono); font-size: calc(8.5px * var(--kess-fs-labels, 1)); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--kess-ink-soft);
}
.kess-cardfoot { padding: 9px 13px; border-top: 1px solid var(--kess-line); }

/* ---- the dashboard deck ----------------------------------------------------------------------

   Three stacks of cards, each card the same frame: a head, a body shaped like the thing it holds,
   and a footer that is one accented link into the section with the rest of it. Every list stops at
   five rows - a dashboard is a summary, and the sixth row is what the section is for.
*/

/* Tab pills. Two cards carry a pair of faces - who you are / your papers, what is waiting on you /
   what is waiting on your word - and the head's badge and the footer's link both follow the pill. */
.kess-pills { display: flex; gap: 2px; flex-wrap: wrap; }
.kess-pill {
  border: 0; background: transparent; cursor: pointer;
  border-radius: var(--kess-r-btn); padding: 7px 10px;
  font-family: inherit; font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 600; line-height: 1;
  color: var(--kess-ink-3);
  transition: background .13s ease, color .13s ease;
}
.kess-pill:hover { color: var(--kess-ink); }
.kess-pill.is-active { background: color-mix(in srgb, var(--kess-accent-hex) 12%, transparent); color: var(--kess-accent); }
.kess-pill:focus-visible { outline: none; box-shadow: var(--kess-ring); }

/* A segmented control - the calendar's Events/Holidays. The chosen face lifts off the trough. */
.kess-seg { display: inline-flex; background: var(--kess-sunk); border-radius: var(--kess-r-tile); padding: 2px; }
.kess-seg-btn {
  border: 0; background: transparent; cursor: pointer;
  border-radius: var(--kess-r-sm); padding: 6px 10px;
  font-family: inherit; font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 600; line-height: 1;
  color: var(--kess-ink-3);
}
.kess-seg-btn.is-active {
  background: var(--kess-surface); color: var(--kess-ink);
  box-shadow: 0 1px 2px rgba(23, 26, 31, .12);
}
.kess-seg-btn:focus-visible { outline: none; box-shadow: var(--kess-ring); }

/* The ruled list every card body that is a list is made of. */
.kess-rows { display: flex; flex-direction: column; }
.kess-row {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 13px;
  border-bottom: 1px solid var(--kess-line);
  transition: background .13s ease;
}
.kess-row:last-child { border-bottom: 0; }
.kess-row.is-hover:hover { background: var(--kess-surface-2); }
.kess-row.is-mid { align-items: center; }
.kess-row-body { min-width: 0; flex: 1 1 auto; }
.kess-row-title { font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 600; line-height: 1.35; color: var(--kess-ink); }
.kess-row-sub { font-size: calc(10.5px * var(--kess-fs-secondary, 1)); line-height: 1.35; color: var(--kess-ink-3); }
.kess-row-side { flex: none; display: flex; align-items: center; gap: 6px; }

/* The footer link. The only place the accent is used as a link inside a card. */
.kess-linkfoot { padding: 9px 13px; }
.kess-link {
  border: 0; background: transparent; padding: 0; cursor: pointer;
  font-family: inherit; font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 500; color: var(--kess-accent);
}
.kess-link:hover { color: var(--kess-accent); text-decoration: underline; }
.kess-link:focus-visible { outline: none; box-shadow: var(--kess-ring); border-radius: 3px; }

/* Who you are: label over value, as many to a row as the card is wide enough for. */
.kess-fieldgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  column-gap: 18px; row-gap: 13px; padding: 3px 13px 11px;
}
.kess-fieldgrid > .kess-field { padding: 10px 0; margin-bottom: 0; border-bottom: 1px solid var(--kess-line); min-width: 0; }
.kess-fieldgrid.is-end { clip-path: inset(0 0 12px 0); }
.kess-field-label {
  font-family: var(--kess-mono);
  font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 500; line-height: 1.4; letter-spacing: .1em;
  text-transform: uppercase; color: var(--kess-ink-3); margin-bottom: 4px;
}
.kess-field-value { font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 500; line-height: 1.4; color: var(--kess-ink); word-break: break-word; }

/* Documents are objects you take away, so they are cards with a type mark, not rows to scan. */
.kess-doccards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 9px; padding: 12px 12px 4px;
}
.kess-doccard {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px; min-width: 0;
  border: 1px solid var(--kess-inner); border-radius: var(--kess-r-md);
  transition: border-color .13s ease, background .13s ease;
}
.kess-doccard:hover { border-color: var(--kess-border-2); background: var(--kess-surface-2); }
.kess-doccard-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 6px; }
.kess-doccard-name { font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 600; line-height: 1.3; color: var(--kess-ink); }
.kess-doccard-expiry { font-size: calc(10.5px * var(--kess-fs-secondary, 1)); line-height: 1.35; color: var(--kess-ink-3); }
.kess-doccard-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 6px; }

/* The lettered tile standing in for a document type, and its cousin on the contract card. Not
   `.kess-tile`: that name belongs to the course card further down, and while both held it the two
   rules ran together and each drew the other's shape. */
.kess-lettertile {
  flex: none; width: 26px; height: 26px; border-radius: var(--kess-r-tile);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--kess-mono); font-size: 9.5px; font-weight: 600; letter-spacing: .02em;
  background: var(--kess-slate-wash); color: var(--kess-slate);
}
.kess-orgmark {
  flex: none; width: 30px; height: 30px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--kess-mono); font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 600;
  background: var(--kess-accent); color: #fff;
}

/* A span of time with a position in it: the contract's term, and the shift where one is drawn. */
.kess-trackrow {
  display: flex; justify-content: space-between; gap: 10px;
  font-family: var(--kess-mono); font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 500;
  letter-spacing: .06em; color: var(--kess-ink-3);
}
.kess-track { height: 7px; border-radius: var(--kess-r-track); background: var(--kess-sunk); overflow: hidden; }
.kess-track-fill { height: 100%; background: var(--kess-accent); border-radius: var(--kess-r-track); }
.kess-track-now { color: var(--kess-accent); }

/* Label and value on one line, right-aligned - the contract's facts, which are read as a column. */
.kess-defrow {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--kess-line);
}
.kess-defrow:last-child { border-bottom: 0; }
.kess-defrow-key {
  font-family: var(--kess-mono); flex: none;
  font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 500; line-height: 1.4; letter-spacing: .1em;
  text-transform: uppercase; color: var(--kess-ink-3);
}
.kess-defrow-value { font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 500; line-height: 1.4; text-align: right; color: var(--kess-ink); min-width: 0; }

/* What you are paid, set as the one figure on the card that is worth reading from across a desk. */
.kess-money { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.kess-money-value {
  font-family: var(--kess-mono);
  font-size: calc(28px * var(--kess-fs-figures, 1)); font-weight: 600; letter-spacing: -.02em; line-height: 1; color: var(--kess-ink);
  font-variant-numeric: tabular-nums;
}
.kess-money-unit { font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 500; color: var(--kess-ink-3); }

.kess-sal-hero { display: flex; align-items: center; justify-content: space-between; gap: 14px 20px; flex-wrap: wrap; padding: 15px 16px; }
.kess-sal-who { display: flex; align-items: center; gap: 11px; min-width: 0; flex: 1 1 240px; }
.kess-sal-contract { font-size: calc(13.5px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink); margin-bottom: 2px; }
.kess-sal-total { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; }
.kess-sal-heads { border-top: 1px solid var(--kess-line); padding: 4px 16px 14px; }
.kess-sal-group {
  display: flex; justify-content: space-between; gap: 10px; padding: 11px 0 7px;
  font-family: var(--kess-mono); font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--kess-ink-3);
}
.kess-sal-heads > .kess-sal-tiles:first-child { margin-top: 10px; }
.kess-sal-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.kess-sal-tile { display: flex; flex-direction: column; justify-content: space-between; min-width: 0; padding: 9px 11px; border-radius: var(--kess-r-tile); background: var(--kess-surface-2); border: 1px solid var(--kess-line); }
.kess-sal-name {
  font-size: calc(11px * var(--kess-fs-secondary, 1)); line-height: 1.3; color: var(--kess-ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.kess-sal-amount { margin-top: 4px; font-size: calc(13px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink); font-variant-numeric: tabular-nums; }
.kess-sal-foot { border-top: 1px solid var(--kess-line); background: var(--kess-surface-2); border-radius: 0 0 var(--kess-r-card) var(--kess-r-card); overflow: hidden; }
.kess-sal-foot .kess-def { border-bottom: 0; border-right-color: var(--kess-line); }

.kess-slip-years { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.kess-slips { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; padding: 13px; }
.kess-slip {
  display: flex; flex-direction: column; gap: 6px; min-width: 0;
  padding: 11px 12px 12px; border: 1px solid var(--kess-border); border-radius: var(--kess-r-tile);
  background: var(--kess-surface); transition: border-color .13s ease, background .13s ease;
}
.kess-slip:hover { border-color: var(--kess-border-2); background: var(--kess-surface-2); }
.kess-slip-top { display: flex; align-items: center; gap: 7px; min-width: 0; }
.kess-slip-month { font-size: calc(13px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink); }
.kess-slip-latest { margin-left: auto; }
.kess-slip-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }

@media (max-width: 560px) {
  .kess-sal-total { align-items: flex-start; }
  .kess-sal-tiles { grid-template-columns: 1fr 1fr; }
  .kess-slips { grid-template-columns: 1fr 1fr; padding: 11px; gap: 8px; }
}

/* Twelve months of leave as twelve bars. A chart library would draw this better and cost 300KB and
   an island a morph cannot reach into; the figures are already on the server, so the server draws
   them. Each bar is stacked by type, and the legend names the types with their totals. */
.kess-bars { display: flex; flex-direction: column; }
.kess-bar {
  display: grid; grid-template-columns: 30px minmax(0, 1fr) 18px;
  gap: 8px; align-items: center; padding: 3px 0;
}
.kess-bar-month { font-family: var(--kess-mono); font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 500; color: var(--kess-ink-3); }
.kess-bar-track { display: flex; height: 13px; background: var(--kess-sunk); border-radius: 3px; overflow: hidden; }
.kess-bar-fill { height: 100%; background: var(--kess-bar, var(--kess-accent)); }
.kess-bar-count {
  font-family: var(--kess-mono); font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 600;
  color: var(--kess-ink-soft); text-align: right; font-variant-numeric: tabular-nums;
}
.kess-bar-count.is-zero { color: var(--kess-ink-3); font-weight: 500; }

.kess-legend {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 6px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--kess-line);
}
.kess-legend-item {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  font-size: calc(11px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-soft);
}
.kess-legend-swatch { flex: none; width: 9px; height: 9px; border-radius: 2px; background: var(--kess-bar, var(--kess-accent)); }
.kess-legend-days { color: var(--kess-ink-3); white-space: nowrap; }

/* ---- the mobile app, at the foot of the sidebar ------------------------------------------------

   A card rather than two bare links: the store buttons are the point, and a row of underlined text at
   the bottom of a sidebar reads as leftovers. Same glass as the punch button so the two accented
   things in the portal are recognisably the same material.
*/
.kess-appmodal { max-width: 460px; }
.kess-appmodal-mark {
  flex: none; width: 28px; height: 28px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  background: color-mix(in srgb, var(--kess-accent) 16%, transparent);
  color: var(--kess-accent); font-size: 15px;
}
.kess-appmodal-mark > img { width: 100%; height: 100%; object-fit: cover; }
.kess-appmodal-note { font-size: calc(12px * var(--kess-fs-body, 1)); color: var(--kess-ink-3); margin-bottom: 14px; }
.kess-appmodal-codes { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; }
.kess-appmodal-code { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.kess-appmodal-qr {
  width: 176px; height: 176px; padding: 10px; box-sizing: content-box;
  background: #fff; border-radius: 10px; border: 1px solid var(--kess-border);
}
.kess-appmodal-code > .kess-store { width: 100%; max-width: 196px; }

.kess-store {
  display: flex; align-items: center; gap: 7px; min-width: 0;
  padding: 7px 9px; border-radius: var(--kess-r-btn);
  background: var(--kess-surface);
  border: 1px solid var(--kess-border);
  color: var(--kess-ink-2);
  transition: border-color .13s ease, background .13s ease;
}
.kess-store:hover { background: var(--kess-sunk); border-color: var(--kess-border-2); color: var(--kess-ink); }
.kess-store > .mdi { flex: none; font-size: 15px; line-height: 1; color: var(--kess-ink); }
.kess-store-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.kess-store-eyebrow {
  font-family: var(--kess-mono);
  font-size: calc(7.5px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--kess-ink-3);
}
.kess-store-name { font-size: calc(10.5px * var(--kess-fs-secondary, 1)); font-weight: 600; }

/* ---- the calendar popover --------------------------------------------------------------------

   What is coming: the month drawn as a month, with the birthdays, anniversaries and holidays in it
   listed underneath. Under the header's own button rather than on the dashboard, because it is a
   thing you glance at and dismiss, and the deck is for what you act on.

   Moving between months is a round trip - each month is a real read - so the arrows are wired to
   the component, unlike everything else in the portal, which is Alpine's.
*/
.kess-calpop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 616px; max-width: calc(100vw - 24px);
  background: var(--kess-surface);
  border: 1px solid var(--kess-border); border-radius: var(--kess-r-card);
  box-shadow: var(--kess-pop);
  overflow: hidden;
}
.kess-calpop-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 11px 10px 13px;
  background: var(--kess-surface-2); border-bottom: 1px solid var(--kess-line);
}
.kess-calpop-month { font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink); white-space: nowrap; }
.kess-calpop-nav { display: flex; align-items: center; gap: 2px; }

/* The month and what is in it, side by side: the grid answers "when" and the list answers "what",
   and one under the other pushed the list below the fold of a popover. Under 680px there is not room
   for two columns, so they stack again in the order they used to be in.

   The row is a fixed height rather than the taller of its two halves. A busy month made the list the
   taller one, the grid was stretched to match, and CSS Grid spread the slack between its week rows -
   so the month went airy exactly when there was most to read beside it. The height is the tallest a
   month can be: a header row plus six week rows of 292px-wide cells, which are square. The grid packs
   to the top of it, and the list scrolls inside whatever is left. */
.kess-calpop { --kess-calpop-body: 268px; }
.kess-calpop-body { display: flex; align-items: stretch; height: var(--kess-calpop-body); }
.kess-calpop-cal { flex: 0 0 292px; min-width: 0; }
.kess-calpop-cal > .kess-calgrid { align-content: start; }
.kess-calpop-side {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  display: flex; flex-direction: column;
  border-left: 1px solid var(--kess-line);
}
.kess-calpop-side > .kess-calpop-head { flex: none; background: transparent; }
.kess-calpop-side > .kess-callist { flex: 1 1 auto; min-height: 0; max-height: none; border-top: 0; }
@media (max-width: 680px) {
  .kess-calpop { width: 340px; }
  /* stacked, the two are not sharing a row, so neither has to be held to the other's height */
  .kess-calpop-body { flex-direction: column; height: auto; }
  .kess-calpop-cal { flex: none; }
  .kess-calpop-side { border-left: 0; }
  .kess-calpop-side > .kess-calpop-head { border-top: 1px solid var(--kess-line); }
  .kess-calpop-side > .kess-callist { max-height: 232px; }
}

.kess-calgrid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; padding: 11px 13px 12px; }
.kess-calgrid-head {
  font-family: var(--kess-mono);
  font-size: calc(8.5px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--kess-ink-3); text-align: center; padding-bottom: 4px;
}
.kess-calday {
  position: relative; aspect-ratio: 1; min-height: 30px;
  display: flex; align-items: center; justify-content: center;
  border: 0; background: transparent; border-radius: var(--kess-r-btn);
  font-family: var(--kess-mono); font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 500; color: var(--kess-ink-2);
  font-variant-numeric: tabular-nums;
}
.kess-calday.is-blank { visibility: hidden; }
.kess-calday.is-marked { background: var(--kess-accent-tint); color: var(--kess-accent); font-weight: 600; }
.kess-calday.is-today { background: var(--kess-dark); color: var(--kess-bg); font-weight: 600; }

.kess-callist { max-height: 232px; overflow-y: auto; border-top: 1px solid var(--kess-line); scrollbar-width: thin; }
.kess-callist::-webkit-scrollbar { width: 6px; }
.kess-callist::-webkit-scrollbar-track { background: transparent; }
.kess-callist::-webkit-scrollbar-thumb { background: var(--kess-border-2); border-radius: 3px; }
.kess-calitem { display: flex; align-items: center; gap: 11px; padding: 10px 13px; border-bottom: 1px solid var(--kess-line); }
.kess-calitem:last-child { border-bottom: 0; }
.kess-calitem-lead {
  flex: none; width: 26px; height: 26px; border-radius: var(--kess-r-tile);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--kess-mono); font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 600;
  background: var(--kess-accent-tint); color: var(--kess-accent);
}
.kess-calitem-body { min-width: 0; flex: 1 1 auto; }
.kess-calitem-title { font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 600; line-height: 1.3; color: var(--kess-ink); }
.kess-calitem-sub { font-size: calc(11px * var(--kess-fs-secondary, 1)); line-height: 1.3; color: var(--kess-ink-3); }

/* The count on the header's calendar button: what is in the month being shown. */
.kess-calbtn { background: var(--kess-accent-tint); color: var(--kess-accent); }
.kess-calbtn:hover { background: var(--kess-accent-line); color: var(--kess-accent); }
.kess-calbtn-count {
  position: absolute; top: -3px; right: -3px;
  min-width: 15px; height: 15px; padding: 0 3px; border-radius: var(--kess-r-badge);
  background: var(--kess-accent); color: #fff;
  font-family: var(--kess-mono); font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600; line-height: 15px; text-align: center;
}

/* ---- accordion ------------------------------------------------------------------------------------------ */

.kess-acc {
  border: 1px solid var(--kess-border); border-radius: var(--kess-r-sm);
  background: var(--kess-surface); overflow: hidden;
  transition: box-shadow .16s ease, border-color .16s ease;
}
.kess-acc + .kess-acc { margin-top: 9px; }
.kess-acc.is-open { border-color: var(--kess-accent-line); box-shadow: var(--kess-shadow); }
.kess-acc-head {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  padding: 11px 14px; transition: background .13s ease;
}
.kess-acc-head:hover { background: var(--kess-surface-2); }
/* The head drops its open colour in .16s. The body is collapsed by x-collapse, whose default is
   .25s, so the head finished first and the rest of the travel read as the panel lagging behind it.
   The blade asks for .16s to match; this is the other half of that pair. */
.kess-acc.is-open > .kess-acc-head { background: var(--kess-accent-wash); }
.kess-acc-caret { flex: none; color: var(--kess-ink-3); font-size: 14px; transition: transform .16s ease; }
.kess-acc.is-open > .kess-acc-head .kess-acc-caret { transform: rotate(90deg); color: var(--kess-accent); }
.kess-acc-title { flex: 1 1 auto; min-width: 0; font-size: calc(13px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink); }
.kess-acc-title small { font-weight: 400; color: var(--kess-ink-3); }
.kess-acc-body { padding: 14px; border-top: 1px solid var(--kess-border); }

/* ---- a scanned document page ---------------------------------------------------------------------------
   A policy is a picture of a page. Its own white is the only ground its black text is readable on and
   nothing inside it can be restyled, so the dark theme is not allowed behind it: the tile keeps its
   white in both themes and only the frame around it follows the theme. */

.kess-docpages { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.kess-docpage {
  display: block; width: 100%; max-width: 1000px;
  background: #ffffff;
  border: 1px solid var(--kess-border); border-radius: var(--kess-r-sm);
}

/* ---- tables ------------------------------------------------------------------------------------------------ */

.kess-tablewrap { overflow-x: auto; }
.kess-table { width: 100%; border-collapse: collapse; font-size: calc(12.5px * var(--kess-fs-body, 1)); }
.kess-table > thead > tr > th {
  font-family: var(--kess-mono); letter-spacing: .1em;
  text-align: left; padding: 9px 14px; white-space: nowrap;
  background: var(--kess-surface-2);
  border-bottom: 1px solid var(--kess-border);
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); text-transform: uppercase; letter-spacing: .06em;
  font-weight: 700; color: var(--kess-ink-3);
}
.kess-table > tbody > tr > td { padding: 10px 14px; border-bottom: 1px solid var(--kess-border); vertical-align: middle; }
.kess-table > tbody > tr:last-child > td { border-bottom: 0; }
.kess-table > tbody > tr:hover { background: var(--kess-surface-2); }
.kess-table td.is-num, .kess-table th.is-num { text-align: right; }

/* ---- empty / loading ------------------------------------------------------------------------------------------ */

.kess-empty { padding: 34px 20px; text-align: center; color: var(--kess-ink-3); }
.kess-empty-ico {
  width: 44px; height: 44px; margin: 0 auto 12px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  background: var(--kess-accent-wash); color: var(--kess-accent); font-size: 20px;
}
.kess-empty-title { font-size: calc(13px * var(--kess-fs-body, 1)); font-weight: 600; color: var(--kess-ink-2); }
.kess-empty-note { max-width: 460px; margin: 3px auto 0; font-size: calc(12px * var(--kess-fs-body, 1)); }

.kess-loading { padding: 34px; text-align: center; color: var(--kess-ink-3); font-size: calc(12.5px * var(--kess-fs-body, 1)); }
.kess-spin { display: inline-block; animation: kess-spin 1s linear infinite; transform-origin: 50% 50%; }
@keyframes kess-spin { to { transform: rotate(360deg); } }

.kess-skel {
  height: 12px; border-radius: 6px;
  background: linear-gradient(90deg, var(--kess-sunk) 25%, var(--kess-border) 37%, var(--kess-sunk) 63%);
  background-size: 400% 100%;
  animation: kess-shimmer 1.3s ease infinite;
}
@keyframes kess-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

.kess-progress { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 100; overflow: hidden; }
.kess-progress::after {
  content: ""; display: block; height: 100%; width: 40%;
  background: var(--kess-accent);
  animation: kess-progress 1s ease-in-out infinite;
}
@keyframes kess-progress { 0% { transform: translateX(-100%); } 100% { transform: translateX(350%); } }

.kess-pageskel { display: none; flex-direction: column; gap: 12px; }
.kess-root.is-opening .kess-pageskel { display: flex; }
.kess-root.is-opening .kess-main > :not(.kess-pageskel) { display: none; }
.kess-pageskel-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.kess-pageskel-tile { padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.kess-pageskel-block { padding: 18px; display: flex; flex-direction: column; gap: 12px; }
.kess-pageskel .kess-skel.is-heading { width: 28%; height: 16px; margin: 4px 0 2px; }
.kess-pageskel .kess-skel.is-label { width: 45%; height: 10px; }
.kess-pageskel .kess-skel.is-figure { width: 32%; height: 22px; }
.kess-pageskel .kess-skel.is-title { width: 36%; height: 14px; margin-bottom: 4px; }
.kess-pageskel-block .kess-skel:nth-child(3n + 2) { width: 92%; }
.kess-pageskel-block .kess-skel:nth-child(3n) { width: 78%; }
.kess-pageskel-block .kess-skel:nth-child(3n + 1):not(.is-title) { width: 64%; }
@media (max-width: 560px) {
  .kess-pageskel-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kess-pageskel-tile:nth-child(3) { display: none; }
}

/* ---- notices ---------------------------------------------------------------------------------------------------- */

.kess-notice {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 14px; border-radius: var(--kess-r-sm);
  border: 1px solid var(--kess-border); background: var(--kess-sunk);
  font-size: calc(12.5px * var(--kess-fs-body, 1)); color: var(--kess-ink);
}
.kess-notice > .ksty { flex: none; margin-top: 1px; font-size: 16px; }
.kess-notice.is-info    { background: var(--kess-primary-wash); border-color: var(--kess-accent-line); }
.kess-notice.is-info    > .ksty { color: var(--kess-primary); }
.kess-notice.is-success { background: var(--kess-success-wash); border-color: transparent; }
.kess-notice.is-success > .ksty { color: var(--kess-success); }
.kess-notice.is-warning { background: var(--kess-warning-wash); border-color: transparent; }
.kess-notice.is-warning > .ksty { color: var(--kess-warning); }
.kess-notice.is-danger  { background: var(--kess-danger-wash);  border-color: transparent; }
.kess-notice.is-danger  > .ksty { color: var(--kess-danger); }

/* a notice rendered as a whole screen, with nothing around it */
.kess-root > .kess-notice,
.kess-root > div > .kess-notice { margin: 16px; }

/* ---- toasts ------------------------------------------------------------------------------------------------------
   Drawn by the document rather than by a section a morph could replace mid-animation. */
.kess-toasts {
  position: fixed; right: 16px; bottom: calc(16px + var(--kess-footer)); z-index: 90;
  display: flex; flex-direction: column; gap: 8px;
  max-width: min(360px, calc(100vw - 32px));
}
.kess-toast {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 13px; border-radius: var(--kess-r-sm);
  background: var(--kess-surface); border: 1px solid var(--kess-border);
  border-left: 3px solid var(--kess-slate);
  box-shadow: var(--kess-lift); font-size: calc(12.5px * var(--kess-fs-body, 1)); cursor: pointer;
}
.kess-toast > .ksty { flex: none; margin-top: 1px; font-size: 15px; }
.kess-toast.is-success { border-left-color: var(--kess-success); }
.kess-toast.is-success > .ksty { color: var(--kess-success); }
.kess-toast.is-error { border-left-color: var(--kess-danger); }
.kess-toast.is-error > .ksty { color: var(--kess-danger); }
.kess-toast.is-warning { border-left-color: var(--kess-warning); }
.kess-toast.is-warning > .ksty { color: var(--kess-warning); }

/* ---- dialogs ------------------------------------------------------------------------------------------------------ */

.kess-modal { position: fixed; inset: 0; z-index: 80; display: flex; align-items: flex-start; justify-content: center; padding: 24px 16px; overflow-y: auto; }
.kess-modal-scrim { position: fixed; inset: 0; background: rgba(16, 22, 33, .5); }
.kess-modal-card {
  position: relative; width: 100%; max-width: 560px; margin: auto 0;
  background: var(--kess-surface); border: 1px solid var(--kess-border);
  border-radius: var(--kess-r); box-shadow: var(--kess-lift); overflow: hidden;
}
.kess-modal-head { display: flex; align-items: center; gap: 9px; padding: 13px 16px; border-bottom: 1px solid var(--kess-border); }
.kess-modal-body { padding: 16px; }

/* ---- forms ------------------------------------------------------------------------------------------------------
   The portal's own controls and the Bootstrap ones that arrive inside borrowed components. */

.kess-field { min-width: 0; margin-bottom: 13px; }
.kess-field:last-child { margin-bottom: 0; }
.kess-field > label,
.kess-label {
  display: block; margin-bottom: 5px;
  font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 650; letter-spacing: .03em; color: var(--kess-ink-2);
}
.kess-field-note { margin-top: 4px; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }
.kess-field-error { margin-top: 4px; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-danger); }
.kess-formgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 14px; }

:is(.kess-root, .kess-portal) .kess-input,
:is(.kess-root, .kess-portal) .form-control,
:is(.kess-root, .kess-portal) .form-select,
:is(.kess-root, .kess-portal) input[type="text"],
:is(.kess-root, .kess-portal) input[type="password"],
:is(.kess-root, .kess-portal) input[type="number"],
:is(.kess-root, .kess-portal) input[type="email"],
:is(.kess-root, .kess-portal) input[type="tel"],
:is(.kess-root, .kess-portal) input[type="date"],
:is(.kess-root, .kess-portal) input[type="month"],
:is(.kess-root, .kess-portal) input[type="search"],
:is(.kess-root, .kess-portal) select,
:is(.kess-root, .kess-portal) textarea {
  width: 100%; height: 36px; padding: 6px 11px;
  font-family: inherit; font-size: calc(13px * var(--kess-fs-body, 1)); line-height: 1.5;
  color: var(--kess-ink); background-color: var(--kess-surface);
  border: 1px solid var(--kess-border-2); border-radius: var(--kess-r-sm);
  box-shadow: none;
  transition: border-color .13s ease, box-shadow .13s ease;
}
:is(.kess-root, .kess-portal) textarea { height: auto; min-height: 76px; resize: vertical; }
:is(.kess-root, .kess-portal) input[type="file"] { height: auto; padding: 6px 10px; }

:is(.kess-root, .kess-portal) .kess-input:focus,
:is(.kess-root, .kess-portal) .form-control:focus,
:is(.kess-root, .kess-portal) input:focus,
:is(.kess-root, .kess-portal) select:focus,
:is(.kess-root, .kess-portal) textarea:focus {
  outline: none; border-color: var(--kess-accent); box-shadow: var(--kess-ring);
}
:is(.kess-root, .kess-portal) input::placeholder,
:is(.kess-root, .kess-portal) textarea::placeholder { color: var(--kess-ink-3); }
:is(.kess-root, .kess-portal) input[disabled],
:is(.kess-root, .kess-portal) select[disabled],
:is(.kess-root, .kess-portal) textarea[disabled],
:is(.kess-root, .kess-portal) .form-control[disabled],
:is(.kess-root, .kess-portal) .form-control[readonly] { background-color: var(--kess-sunk); color: var(--kess-ink-2); cursor: default; }

/* a date input's own picker glyph is black, which disappears on a dark ground */
[data-kess-theme="dark"] :is(.kess-root, .kess-portal) input[type="date"]::-webkit-calendar-picker-indicator,
[data-kess-theme="dark"] :is(.kess-root, .kess-portal) input[type="month"]::-webkit-calendar-picker-indicator { filter: invert(.75); }

/* Pairs up the bare label/field siblings the framework's UI component emits — a `label.col-md-3`
   then a `div.col-md-9` with no wrapper of its own, so the container has to be the grid. */
.kess-fieldrows { display: grid; grid-template-columns: 180px minmax(0, 1fr); align-items: center; gap: 13px 16px; }
.kess-fieldrows > label {
  grid-column: 1; float: none; width: auto; margin: 0; padding: 0;
  font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 650; letter-spacing: .03em; line-height: 1.35; color: var(--kess-ink-2);
}
.kess-fieldrows > div[class*="col-"] { grid-column: 2; float: none; width: auto; padding: 0; min-width: 0; }
@media (max-width: 760px) {
  .kess-fieldrows { grid-template-columns: minmax(0, 1fr); gap: 4px 0; }
  .kess-fieldrows > label { grid-column: 1; margin-top: 9px; }
  .kess-fieldrows > div[class*="col-"] { grid-column: 1; }
}

/* ---- the ERP's form component, in the portal's own clothes ---------------------------------------

   KFormBuilder draws each field by including `{base_view}.{uitype}`, so the portal hands it a base
   view of its own - `custom.ui.inc.kess` - and the fields arrive as `.kess-field` rather than as
   Bootstrap form groups. The component's own wrapper is not ours, though: it is fixed in render(),
   and it drops the error block, the fields and the Save button in as flat siblings. So the grid is
   declared here, on that wrapper, and the two things that are not fields are spanned across it.

   A field with no partial in the set is silently skipped by KFormBuilder, so the set has to cover
   every type a form uses - text, rel-b1, file and date today, plus alert and button. */
.kess-formmount > div { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0 18px; align-items: start; }
.kess-formmount > div > [id^="kformbuilder_errors_"],
.kess-formmount > div > .kess-formtabs,
.kess-formmount > div > .kform-tabpane,
.kess-formmount > div > .kess-formsubmit { grid-column: 1 / -1; }
.kess-formmount > div > .kform-tabpane { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0 18px; align-items: start; }
.kess-formmount .kess-field { margin-bottom: 14px; }
.kess-formsubmit { margin-top: 4px; }

.kess-filefield { display: flex; align-items: flex-start; gap: 10px; }
.kess-filethumb {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px; padding: 3px;
  background: var(--kess-surface); border: 1px solid var(--kess-border); border-radius: var(--kess-r-tile);
}
.kess-filethumb > img { max-width: 100%; max-height: 100%; object-fit: contain; }
.kess-filebar { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-top: 5px; }
.kess-inputrow { display: flex; align-items: center; gap: 7px; }
.kess-inputrow > .kess-input { min-width: 0; }
.kess-link.is-danger { color: var(--kess-danger); }

/*
  select2, on stock select2 CSS.

  Its own sheet sizes a single control at 28px with a 28px line-height on the label and a floated
  clear button, none of which survives being resized to the portal's 36px: the label sits high and the
  cross drifts off the arrow. So the control is laid out here rather than patched - the label is
  centred by line-height inside a padding-free box, and the arrow and the clear are placed against the
  right edge instead of floated.
*/
:is(.kess-root, .kess-portal) .select2-container { max-width: 100%; width: 100% !important; }

/*
  ...except the one select2 appends for the open dropdown, which is a child of the portal root rather
  than of the field. `width: 100%` on that is the full page, and select2 has already placed it at the
  field's own left offset - so the page grew by however far across the field sat and the portal got a
  horizontal scrollbar every time a dropdown opened. The dropdown inside it carries its own inline
  px width, measured from the field, so there is nothing to put back.

  Two rules, not one list: a browser that does not understand `:has()` drops the whole selector list
  it appears in, and the child rule is the one that matters.
*/
:is(.kess-root, .kess-portal) > .select2-container { width: auto !important; max-width: none; }
:is(.kess-root, .kess-portal) .select2-container:has(> .select2-dropdown) { width: auto !important; max-width: none; }

:is(.kess-root, .kess-portal) .select2-container .select2-selection--single {
  position: relative;
  height: 36px; padding: 0;
  background: var(--kess-surface);
  border: 1px solid var(--kess-border-2);
  border-radius: var(--kess-r-sm);
  box-shadow: none;
}
:is(.kess-root, .kess-portal) .select2-container .select2-selection--single .select2-selection__rendered {
  height: 34px; line-height: 34px;
  padding: 0 52px 0 11px; margin: 0;
  font-size: calc(13px * var(--kess-fs-body, 1)); color: var(--kess-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
:is(.kess-root, .kess-portal) .select2-container .select2-selection--single .select2-selection__placeholder { color: var(--kess-ink-3); }

/* both placed against the right edge, so they line up with each other and with the label's centre */
:is(.kess-root, .kess-portal) .select2-container .select2-selection--single .select2-selection__arrow {
  position: absolute; top: 0; right: 7px;
  width: 16px; height: 34px;
}
:is(.kess-root, .kess-portal) .select2-container .select2-selection--single .select2-selection__clear {
  position: absolute; top: 0; right: 29px; float: none;
  width: 16px; height: 34px; margin: 0; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 400; line-height: 1; color: var(--kess-ink-3);
}
:is(.kess-root, .kess-portal) .select2-container .select2-selection--single .select2-selection__clear:hover { color: var(--kess-danger); }
:is(.kess-root, .kess-portal) .select2-container .select2-selection--single .select2-selection__clear > span { line-height: 1; }

/* the stock arrow is a border triangle; this is the same chevron the icon set draws everywhere else */
:is(.kess-root, .kess-portal) .select2-container .select2-selection__arrow b {
  position: absolute; top: 50%; left: 50%;
  width: 14px; height: 14px; margin: 0; border: 0;
  transform: translate(-50%, -50%);
  background: var(--kess-ink-3);
  -webkit-mask: url("svgicons/chevron-down.svg") center / contain no-repeat;
  mask: url("svgicons/chevron-down.svg") center / contain no-repeat;
}
:is(.kess-root, .kess-portal) .select2-container--open .select2-selection__arrow b { transform: translate(-50%, -50%) rotate(180deg); }

:is(.kess-root, .kess-portal) .select2-container .select2-selection--multiple {
  min-height: 36px; padding: 0 4px 4px;
  background: var(--kess-surface);
  border: 1px solid var(--kess-border-2);
  border-radius: var(--kess-r-sm);
}
:is(.kess-root, .kess-portal) .select2-container .select2-selection--multiple .select2-selection__rendered { padding: 0; margin: 0; }
:is(.kess-root, .kess-portal) .select2-container .select2-selection__choice {
  margin: 4px 4px 0 0; padding: 3px 9px;
  background: var(--kess-accent-wash); color: var(--kess-accent-2);
  border: 0; border-radius: var(--kess-r-xs);
  font-size: calc(12px * var(--kess-fs-body, 1)); line-height: 1.55;
}
:is(.kess-root, .kess-portal) .select2-container .select2-selection__choice__remove { margin-right: 6px; color: var(--kess-accent-2); opacity: .7; border: 0; background: none; }
:is(.kess-root, .kess-portal) .select2-container .select2-selection__choice__remove:hover { opacity: 1; color: var(--kess-danger); background: none; }
:is(.kess-root, .kess-portal) .select2-container .select2-search--inline .select2-search__field { height: 26px; margin-top: 5px; font-size: calc(13px * var(--kess-fs-body, 1)); color: var(--kess-ink); }

:is(.kess-root, .kess-portal) .select2-container--focus .select2-selection--single,
:is(.kess-root, .kess-portal) .select2-container--open .select2-selection--single,
:is(.kess-root, .kess-portal) .select2-container--focus .select2-selection--multiple,
:is(.kess-root, .kess-portal) .select2-container--open .select2-selection--multiple {
  border-color: var(--kess-accent);
  box-shadow: var(--kess-ring);
}
:is(.kess-root, .kess-portal) .select2-container--disabled .select2-selection--single,
:is(.kess-root, .kess-portal) .select2-container--disabled .select2-selection--multiple { background: var(--kess-sunk); color: var(--kess-ink-2); }

/* The dropdown, dropped inside the portal by `dropdownParent` so these rules reach it. */
:is(.kess-root, .kess-portal) .select2-container--open .select2-dropdown {
  background: var(--kess-surface);
  border: 1px solid var(--kess-border-2);
  border-radius: var(--kess-r-sm);
  box-shadow: var(--kess-lift);
  overflow: hidden;
}
:is(.kess-root, .kess-portal) .select2-dropdown .select2-search--dropdown { padding: 7px; }
:is(.kess-root, .kess-portal) .select2-dropdown .select2-search__field {
  height: 32px; padding: 5px 9px;
  border: 1px solid var(--kess-border-2); border-radius: var(--kess-r-xs);
  background: var(--kess-surface); color: var(--kess-ink); font-size: calc(12.5px * var(--kess-fs-body, 1));
}
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__options { max-height: 260px; }
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__option {
  padding: 7px 11px; font-size: calc(12.5px * var(--kess-fs-body, 1)); color: var(--kess-ink); background: transparent;
}
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__option--highlighted,
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__option--highlighted[aria-selected] {
  background: var(--kess-sunk); color: var(--kess-ink);
}

/* What is already chosen is marked in the list, with a tick rather than only a shade - a wash alone
   reads the same as the row the pointer happens to be over. */
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__option[aria-selected="true"] {
  display: flex; align-items: center; gap: 8px;
  background: var(--kess-accent-wash); color: var(--kess-accent-2); font-weight: 600;
}
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__option[aria-selected="true"]::after {
  content: ""; flex: none; margin-left: auto;
  width: 14px; height: 14px;
  background: currentColor;
  -webkit-mask: url("svgicons/check.svg") center / contain no-repeat;
  mask: url("svgicons/check.svg") center / contain no-repeat;
}
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__message,
:is(.kess-root, .kess-portal) .select2-dropdown .select2-results__option.loading-results { color: var(--kess-ink-3); font-size: calc(12.5px * var(--kess-fs-body, 1)); }

/* ---- borrowed markup -----------------------------------------------------------------------------------------------
   `.kess-guest` wraps a component the portal did not write — the punch card, the attendance grid, the
   request form. It flattens their Bootstrap chrome and leaves the content alone. */

.kess-guest .card,
.kess-guest .panel { margin: 0 !important; border: 0 !important; border-radius: 0 !important; box-shadow: none !important; background: transparent !important; }
.kess-guest .card-header,
.kess-guest .panel-heading {
  padding: 0 0 10px !important; margin: 0 0 12px !important;
  background: transparent !important; border: 0 !important; border-bottom: 1px solid var(--kess-border) !important;
  font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--kess-ink-3) !important;
}
.kess-guest .card-body,
.kess-guest .panel-body { padding: 0 !important; }
.kess-guest .card-footer { padding: 10px 0 0 !important; background: transparent !important; border-top: 1px solid var(--kess-border) !important; }

.kess-guest .alert {
  padding: 11px 14px; border-radius: var(--kess-r-sm);
  border: 1px solid var(--kess-border); background: var(--kess-sunk); color: var(--kess-ink);
  font-size: calc(12.5px * var(--kess-fs-body, 1));
}
.kess-guest .alert-success { background: var(--kess-success-wash); border-color: transparent; color: var(--kess-ink); }
.kess-guest .alert-danger  { background: var(--kess-danger-wash);  border-color: transparent; color: var(--kess-ink); }
.kess-guest .alert-warning { background: var(--kess-warning-wash); border-color: transparent; color: var(--kess-ink); }
.kess-guest .alert-info    { background: var(--kess-primary-wash); border-color: transparent; color: var(--kess-ink); }

.kess-guest .btn {
  height: 34px; padding: 0 13px;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border-radius: var(--kess-r-sm); border: 1px solid var(--kess-border-2);
  background: var(--kess-surface); color: var(--kess-ink-2);
  font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 550; box-shadow: none;
}
.kess-guest .btn:hover { background: var(--kess-surface-2); color: var(--kess-ink); }
.kess-guest .btn-primary, .kess-guest .btn-info { background: var(--kess-accent); border-color: var(--kess-accent); color: #fff; }

/* The request form is not a guest in Bootstrap's clothes - it has a design system of its own, and a
   hardcoded blue accent with it. Inside the portal only its accent tokens are re-pointed, so its
   submit button, focus rings and chips follow the installation's colour like everything else. */
:is(.kess-root, .kess-portal) .kreq {
  --kreq-accent: var(--kess-accent);
  --kreq-accent-2: var(--kess-accent-2);
  --kreq-ring: var(--kess-ring);
}
.kess-guest .btn-success { background: var(--kess-success-2); border-color: var(--kess-success-2); color: #fff; }
.kess-guest .btn-danger  { background: var(--kess-danger-2);  border-color: var(--kess-danger-2);  color: #fff; }
.kess-guest .btn-sm { height: 28px; padding: 0 10px; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); }

.kess-guest .table { margin: 0; font-size: calc(12.5px * var(--kess-fs-body, 1)); color: var(--kess-ink); }
.kess-guest .table > :not(caption) > * > * { padding: 10px 14px; background: transparent; color: var(--kess-ink); border-bottom-color: var(--kess-border); }
.kess-guest .table thead th {
  background: var(--kess-surface-2);
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: var(--kess-ink-3);
}
.kess-guest .badge { border-radius: var(--kess-r-pill); font-size: calc(11px * var(--kess-fs-secondary, 1)); font-weight: 600; }
.kess-guest .text-muted { color: var(--kess-ink-3) !important; }
.kess-guest .bg-light { background: var(--kess-sunk) !important; }
.kess-guest .border { border-color: var(--kess-border) !important; }
.kess-guest hr { border-top-color: var(--kess-border); }

.kess-guest .table > :not(caption) > * > * { vertical-align: middle; }

.kess-clip { overflow-x: auto; }

/* ---- the attendance month -----------------------------------------------------------------------------------------
   A calendar of day cards, and no table. The card is the whole record of the day - status, punches,
   effective and gross hours, arrival, remarks, any rejection reason - so nothing has to be opened to
   read a month. The only dialog left is the regularisation reason, which is a form and cannot live in
   a 150px column.

   The range is the payroll period, not the calendar month - it often starts mid-month - so the
   calendar is a run of whole weeks over whatever the period is, with blanks at each end.

   A day carries one colour, `--kess-att-mark`, used for its dot, its bar and its left edge. Only the
   four kinds of day that are NOT an ordinary worked day also wash their background: colour means
   exception here, and tinting every cell would make the month a rainbow with nothing standing out. */

.kess-att-tone.is-ok          { --kess-att-mark: var(--kess-teal); }
.kess-att-tone.is-short       { --kess-att-mark: var(--kess-warning); }
.kess-att-tone.is-pending     { --kess-att-mark: var(--kess-warning); }
.kess-att-tone.is-rejected    { --kess-att-mark: var(--kess-danger); }
.kess-att-tone.is-regularized { --kess-att-mark: var(--kess-success); }
.kess-att-tone.is-holiday     { --kess-att-mark: var(--kess-primary); }
.kess-att-tone.is-leave       { --kess-att-mark: var(--kess-violet); }
.kess-att-tone.is-off         { --kess-att-mark: var(--kess-slate); }
.kess-att-tone.is-absent      { --kess-att-mark: var(--kess-danger); }

/* The wash is stronger on the dark ground, where the same mix all but disappears. */
.kess-root, .kess-portal { --kess-att-tint: 8%; }
[data-kess-theme="dark"] .kess-root,
[data-kess-theme="dark"] .kess-portal,
[data-kess-theme="dark"].kess-root,
[data-kess-theme="dark"].kess-portal { --kess-att-tint: 17%; }

.kess-att-cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.kess-att-cal-head {
  padding-bottom: 2px; text-align: center;
  font-family: var(--kess-mono); font-size: calc(9.5px * var(--kess-fs-labels, 1)); font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--kess-ink-3);
}

/* The cell is read, not clicked. The only control on it is the regularisation button, and only on the
   days that have one. */
.kess-att-cell {
  display: flex; flex-direction: column; gap: 4px;
  min-height: 150px; padding: 7px 8px;
  border: 1px solid var(--kess-border); border-radius: var(--kess-r-tile);
  background: var(--kess-surface);
}

/* Drawn on the cell, so "can I put this day right?" is answered by looking at the month. */
.kess-att-reg {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  width: 100%; height: 22px; margin-top: auto; padding: 0 6px;
  border: 0; border-radius: var(--kess-r-btn);
  background: var(--kess-accent-tint); color: var(--kess-accent);
  font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 600; line-height: 1; cursor: pointer;
}
.kess-att-reg:hover { background: var(--kess-accent-line); }
.kess-att-reg:focus-visible { outline: none; box-shadow: var(--kess-ring); }
.kess-att-reg > .ksty { font-size: 11px; }
.kess-att-cell.is-blank { background: transparent; border-style: dashed; border-color: var(--kess-line); cursor: default; }
.kess-att-cell.is-exception { background: color-mix(in srgb, var(--kess-att-mark) var(--kess-att-tint), var(--kess-surface)); }
.kess-att-cell.is-flagged { border-color: color-mix(in srgb, var(--kess-warning) 45%, var(--kess-border)); }
.kess-att-cell.is-today { box-shadow: inset 0 0 0 2px var(--kess-accent); }

/* Date on the left, the fixes pushed to the right of the same line. It wraps: on a narrow card the
   chips drop to a line of their own, still right-aligned, rather than crushing the date. */
.kess-att-cell-top { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 5px; }
.kess-att-num { font-family: var(--kess-mono); font-size: calc(14px * var(--kess-fs-figures, 1)); font-weight: 600; line-height: 1; }
.kess-att-mon { font-family: var(--kess-mono); font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--kess-ink-3); }
.kess-att-dow { font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 600; color: var(--kess-ink-3); }
.kess-att-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--kess-att-mark); flex: none; }

.kess-att-tag {
  font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 600; line-height: 1.25;
  color: color-mix(in srgb, var(--kess-att-mark) 78%, var(--kess-ink));
  overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
/* Arrival, then the two punches, then the two totals. Exactly two tracks, not `auto-fit`: the pairs
   are pairs, and a track count the browser picks would put In, Out and Eff on one line on a wide card
   and break the reading.

   One rule decides how a pair is drawn: **alone on its row, the value goes to the right of the label;
   sharing a row, it goes under it.** Arrival is always alone, so it is always inline. In/Out and
   Eff/Gross are inline only when the card is too narrow to hold two of them, and a full-width row has
   the room to put the value where it is easiest to compare down the card.

   That narrowness is the CARD's, not the window's, so it is a container query - the same card is
   125px at seven columns on a small laptop and 300px in the reflowed layout on the same screen. Where
   `@container` is not supported the whole block is dropped and the two-track layout stands, which is
   correct down to about a 138px card. */
.kess-att-cell { container-type: inline-size; }

.kess-att-kv { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 6px; margin: 1px 0 0; }
.kess-att-kv > div { min-width: 0; }
.kess-att-kv > div.is-wide { grid-column: 1 / -1; display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.kess-att-kv > div.is-wide > dd { text-align: right; }
.kess-att-kv dt {
  font-family: var(--kess-mono); font-size: calc(8.5px * var(--kess-fs-labels, 1)); font-weight: 600; line-height: 1.3;
  letter-spacing: .08em; text-transform: uppercase; color: var(--kess-ink-3);
}
.kess-att-kv dd {
  margin: 0; font-family: var(--kess-mono); font-size: calc(10.5px * var(--kess-fs-secondary, 1)); font-weight: 500; line-height: 1.3;
  color: var(--kess-ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kess-att-kv dd.is-strong { color: var(--kess-ink); font-weight: 600; }

/* 120px of card content is two tracks of 57px, which is the floor for a mono `08:40 AM` beside its
   label. Under it every pair takes its own row and turns inline. */
@container (max-width: 120px) {
  .kess-att-kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kess-att-kv > div { grid-column: 1 / -1; display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
  .kess-att-kv > div > dd { text-align: right; }
}

/* Where a punch was made, when anything recorded it - one chip per fix, its own time and direction on
   it and the coordinates in the tooltip, opening OpenStreetMap. Most installations will never draw
   one: only punches that arrive through the biometrics sync with coordinates carry a fix. */
.kess-att-pins { display: flex; flex-wrap: wrap; gap: 3px; margin-left: auto; }
.kess-att-pin {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 5px; border-radius: var(--kess-r-badge);
  background: var(--kess-sunk); color: var(--kess-ink-2);
  font-family: var(--kess-mono); font-size: calc(9px * var(--kess-fs-labels, 1)); font-weight: 600; line-height: 1.6;
  text-decoration: none; white-space: nowrap;
}
.kess-att-pin:hover { background: var(--kess-accent-tint); color: var(--kess-accent); }
.kess-att-pin:focus-visible { outline: none; box-shadow: var(--kess-ring); }
.kess-att-pin > .ksty { font-size: 10px; }

.kess-att-note {
  font-size: calc(9.5px * var(--kess-fs-labels, 1)); line-height: 1.35; color: var(--kess-ink-3);
  overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
}
.kess-att-note.is-danger { color: var(--kess-danger); }
.kess-att-note > b { font-family: var(--kess-mono); font-size: calc(8.5px * var(--kess-fs-labels, 1)); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--kess-ink-3); }

/* A 24-hour strip the width of the cell, so the shape of the day is readable without opening it. */
.kess-att-mini { position: relative; height: 4px; border-radius: 2px; background: var(--kess-inner); }
.kess-att-mini > i { position: absolute; top: 0; bottom: 0; min-width: 2px; border-radius: 2px; background: var(--kess-att-mark); }

/* A week grid is seven columns or it is not a week grid, so this is the one thing on the screen that
   cannot reflow on its own and needs a breakpoint. Below it the month becomes a run of day cards
   filling whatever width there is.

   1000px, not 780: the portal's content is the viewport less the rail and the gutters, about 900px
   here, which is seven cards of ~125px - already the floor for what a card now carries. Anything
   narrower squeezes them rather than showing a month.

   Weekday alignment is what is given up, and it is the only thing that needs seven columns; the
   weekday is printed on every card, which is why it is there in the wide layout too. The leading and
   trailing blanks exist only to align weeks, so they go with it. */
@media (max-width: 1000px) {
  .kess-att-cal { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
  .kess-att-cal-head, .kess-att-cell.is-blank { display: none; }
}


/* ---- the leave year ------------------------------------------------------------------------------------------------
   Twelve month blocks drawn in the browser off the events the section hands over. One grid per month,
   seven columns, leading blanks so the first lands under its weekday. Leave colours arrive as tokens,
   so the year is one palette and follows the theme. */

.kess-cal { display: grid; grid-template-columns: repeat(auto-fill, minmax(206px, 1fr)); gap: 18px 16px; }
.kess-cal-month { min-width: 0; }
.kess-cal-title {
  margin-bottom: 7px; padding-bottom: 6px;
  border-bottom: 1px solid var(--kess-border);
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--kess-ink-3);
}
.kess-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.kess-cal-head {
  padding-bottom: 3px; text-align: center;
  font-size: calc(9.5px * var(--kess-fs-labels, 1)); font-weight: 700; letter-spacing: .04em; color: var(--kess-ink-3);
}
.kess-cal-day {
  aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
  font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-2);
  transition: box-shadow .13s ease;
}
/* The two weekend columns - the header row takes the first seven cells, so days begin at eight.
   Only the empty ones: a day carrying leave is a filled tile, and the grey it would otherwise win
   by specificity is unreadable on the colour. */
.kess-cal-grid > .kess-cal-day:nth-child(7n):not(.is-event):not(.is-today),
.kess-cal-grid > .kess-cal-day:nth-child(7n + 1):not(.is-event):not(.is-today) { color: var(--kess-ink-3); }
.kess-cal-day.is-blank { visibility: hidden; }
.kess-cal-day.is-today { box-shadow: inset 0 0 0 1.5px var(--kess-border-2); font-weight: 700; color: var(--kess-ink); }
.kess-cal-day.is-event { color: #fff; font-weight: 600; }
.kess-cal-day.is-event.is-today { box-shadow: inset 0 0 0 1.5px var(--kess-ink); }
.kess-cal-day.is-event:hover { box-shadow: var(--kess-shadow); }

.kess-cal-legend {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--kess-border);
}
.kess-cal-key { display: inline-flex; align-items: center; gap: 7px; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-2); }
.kess-cal-key > i { flex: none; width: 10px; height: 10px; border-radius: 3px; }

/* ---- pagination -------------------------------------------------------------------------------------------------------- */

.kess-pager { display: flex; justify-content: flex-end; padding: 12px 16px; border-top: 1px solid var(--kess-border); }
.kess-pager .pagination { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 0; list-style: none; }
.kess-pager .page-item .page-link {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; height: 30px; padding: 0 8px;
  border: 1px solid var(--kess-border); border-radius: var(--kess-r-xs);
  background: var(--kess-surface); color: var(--kess-ink-2); font-size: calc(12px * var(--kess-fs-body, 1));
}
.kess-pager .page-item.active .page-link { background: var(--kess-accent); border-color: var(--kess-accent); color: #fff; }
.kess-pager .page-item.disabled .page-link { opacity: .45; }
.kess-pager svg { width: 12px; height: 12px; }

/* Livewire's bootstrap pager is a nav of two halves: a prev/next pair for narrow screens, and from
   576px up the "Showing 1 to 10 of 13" line beside the numbers. Both sit in a plain wrapper div, so
   the wrapper has to fill the row or the whole nav collapses against the right edge. Its controls are
   buttons, not links, and `fw-semibold` is one of the few classes the grid+utilities build leaves out. */
.kess-pager > div { flex: 1 1 auto; min-width: 0; }
.kess-pager nav { align-items: center; gap: 12px; }
.kess-pager .pagination { margin-left: auto; }
.kess-pager .small { margin: 0; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }
.kess-pager .fw-semibold { font-weight: 600; color: var(--kess-ink-2); }
.kess-pager button.page-link { font-family: inherit; cursor: pointer; }
.kess-pager .page-item.disabled .page-link { cursor: default; }

/* ---- tiles, courses, and the course player ---------------------------------------------------------
   A tile grid for anything read as a block of prose rather than a row: a course is known by its title
   and a paragraph of what it covers, and an About Us panel by a heading and a few sentences - neither
   has anywhere to sit in a table. The player is a document of its own - SCORM content expects to own
   the window it runs in - so it carries its own header rather than the portal's shell. */

.kess-tiles {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
  gap: 14px; padding: 14px 16px; align-items: start;
}
.kess-tile {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
  padding: 14px; background: var(--kess-surface);
  border: 1px solid var(--kess-border); border-radius: var(--kess-r);
}
.kess-tile-body { font-size: calc(12.5px * var(--kess-fs-body, 1)); line-height: 1.6; color: var(--kess-ink-2); }
.kess-tile-body p { margin: 0 0 8px; }
.kess-tile-body p:last-child { margin-bottom: 0; }
.kess-tile-list { margin: 0; padding: 0; list-style: none; font-size: calc(12.5px * var(--kess-fs-body, 1)); color: var(--kess-ink-2); }
.kess-tile-list > li { position: relative; padding: 3px 0 3px 15px; line-height: 1.55; }
.kess-tile-list > li::before {
  content: ""; position: absolute; left: 0; top: 11px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--kess-accent);
}
.kess-course-desc {
  font-size: calc(12.5px * var(--kess-fs-body, 1)); line-height: 1.55; color: var(--kess-ink-2);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.kess-course-desc.is-open { -webkit-line-clamp: unset; overflow: visible; }
.kess-course-foot { margin-top: auto; display: flex; flex-wrap: wrap; gap: 8px; }

/* ---- one team member's requests and workflows -------------------------------------------------------
   Each request and each workflow is its own card rather than a row in a shared one: a request carries a
   label/value grid and a workflow a track of steps, and stacked inside one card those run together into
   a wall with no edge to tell where one ends.

   The step track shows what is OUTSTANDING, never a history - `Support\Team::workflows()` asks only for
   steps that are not DONE, so a finished run has none and says so instead of drawing an empty track. */

.kess-reqhead { display: flex; align-items: flex-start; gap: 10px; }
.kess-reqact { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; border-top: 1px solid var(--kess-line); }

/* ---- the approvals list -----------------------------------------------------------------------------
   One approval step is one line: a face, what it is and who it is about, who it is waiting on, its age,
   and the action. The detail payload is a disclosure under it rather than a third band, because most
   rows are scanned and never read. */

.kess-appr { border-bottom: 1px solid var(--kess-border); }
.kess-appr:last-child { border-bottom: 0; }
.kess-appr:hover { background: var(--kess-surface-2); }
.kess-appr-line { display: flex; align-items: center; gap: 10px; padding: 9px 14px; min-width: 0; }

.kess-appr-body { flex: 1 1 auto; min-width: 0; }
.kess-appr-title {
  font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 650; color: var(--kess-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The person is the thing being scanned for, so it carries the accent rather than the step name. */
.kess-appr-who { font-weight: 600; color: var(--kess-accent-2); }
.kess-appr-meta {
  margin-top: 1px; display: flex; align-items: baseline; gap: 5px; min-width: 0;
  font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); white-space: nowrap; overflow: hidden;
}
.kess-appr-meta > b { font-weight: 600; color: var(--kess-ink-2); }

.kess-appr-side { flex: none; display: flex; align-items: center; gap: 8px; }
.kess-appr-age { font-family: var(--kess-mono); font-size: calc(10px * var(--kess-fs-labels, 1)); color: var(--kess-ink-3); }

/* Narrow: the action drops under the body rather than squeezing the name to nothing. */
@media (max-width: 620px) {
  .kess-appr-line { flex-wrap: wrap; }
  .kess-appr-body { flex: 1 1 100%; order: 2; }
  .kess-appr-side { order: 3; margin-left: auto; }
  .kess-appr-details { padding-left: 14px; }
}

/* ---- team KPI, grouped by person --------------------------------------------------------------------
   One of three layouts being tried on real data; see `Sections\TeamKpi::LAYOUTS`. The person is the
   heading and their evaluations are the rows under it, so a run of months reads as one history rather
   than as five unrelated lines that happen to share a name. */

.kess-kpigroup { border-bottom: 1px solid var(--kess-border); }
.kess-kpigroup:last-child { border-bottom: 0; }
.kess-kpigroup-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; background: var(--kess-surface-2);
  border-bottom: 1px solid var(--kess-line);
}
.kess-kpirow {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 14px 9px 52px;
  border-bottom: 1px solid var(--kess-line);
}
.kess-kpirow:last-child { border-bottom: 0; }
.kess-kpirow-main { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.kess-kpirow-main > .kess-list-note { display: inline-flex; align-items: center; gap: 4px; margin-top: 0; }
@media (max-width: 620px) { .kess-kpirow { padding-left: 14px; } }

.kess-wf {
  margin: 0; padding: 0 0 0 7px; list-style: none;
  border-left: 2px solid var(--kess-border);
  display: flex; flex-direction: column; gap: 13px;
}
.kess-wf-step { position: relative; padding-left: 17px; min-width: 0; }
/* The marker sits on the track, so its colour is the step's status and nothing else carries it. */
.kess-wf-step::before {
  content: ""; position: absolute; left: -14px; top: 4px;
  width: 11px; height: 11px; border-radius: 50%; box-sizing: border-box;
  background: var(--kess-surface); border: 3px solid var(--kess-warning);
}
.kess-wf-step.is-wip::before { border-color: var(--kess-primary); }
.kess-wf-line { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.kess-wf-name { font-size: calc(12.5px * var(--kess-fs-body, 1)); font-weight: 650; color: var(--kess-ink); }
.kess-wf-with {
  margin-top: 3px; display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-2);
}
.kess-wf-with > .ksty { font-size: 12px; color: var(--kess-ink-3); }
.kess-wf-clear { display: flex; align-items: center; gap: 6px; font-size: calc(12px * var(--kess-fs-body, 1)); color: var(--kess-success); }
.kess-wf-clear > .ksty { font-size: 13px; }

/* ---- About Us ---------------------------------------------------------------------------------------
   Seven blocks of the installation's own words and pictures, and they are not seven of the same thing:
   a welcome from a person, a paragraph of introduction, a list of companies, a vision, a set of values,
   a row of faces. Drawn as seven identical cards the page read as a list of cards rather than as a page
   about a company, so each block type gets the shape its content asks for and the stack gives them air.

   The type here runs larger than the rest of the portal on purpose. Every other screen is a working
   screen read in glances; this one is read in paragraphs. */

.kess-about { display: flex; flex-direction: column; gap: 38px; }
.kess-about-sec { min-width: 0; }

/* a heading that names the section without a card head to sit in */
.kess-about-kicker {
  font-size: calc(10.5px * var(--kess-fs-secondary, 1)); font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--kess-accent);
}
.kess-about-h {
  margin: 6px 0 0; font-size: calc(20px * var(--kess-fs-headings, 1)); font-weight: 680; letter-spacing: -.02em; color: var(--kess-ink);
}
.kess-about-h + .kess-about-grid,
.kess-about-h + .kess-about-prose { margin-top: 16px; }

.kess-about-prose { font-size: calc(14px * var(--kess-fs-body, 1)); line-height: 1.75; color: var(--kess-ink-2); max-width: 74ch; }
.kess-about-prose.is-sm { font-size: calc(12.75px * var(--kess-fs-body, 1)); line-height: 1.65; max-width: none; }
.kess-about-prose p { margin: 0 0 11px; }
.kess-about-prose p:last-child { margin-bottom: 0; }
.kess-about-prose strong { color: var(--kess-ink); }

/* the hero: the installation's own image behind a wash, so its type stays readable in both themes
   without the override having to supply two pictures */
.kess-about-hero {
  position: relative; overflow: hidden;
  border-radius: var(--kess-r);
  background-size: cover; background-position: center;
  padding: 58px 28px; text-align: center;
}
.kess-about-hero::before { content: ""; position: absolute; inset: 0; background: var(--kess-hero-wash); }
.kess-about-hero > * { position: relative; }
.kess-about-hero img { max-height: 104px; margin: 0 auto 18px; display: block; }
.kess-about-title { font-size: calc(32px * var(--kess-fs-headings, 1)); font-weight: 700; letter-spacing: -.03em; line-height: 1.15; color: var(--kess-ink); }
.kess-about-note { margin: 10px auto 0; max-width: 62ch; font-size: calc(14.5px * var(--kess-fs-secondary, 1)); font-weight: 500; line-height: 1.6; color: var(--kess-ink-2); }

/* the welcome: a person said this, so the person is in it rather than beside a card head */
.kess-about-welcome { display: flex; gap: 26px; align-items: flex-start; }
.kess-about-portrait { flex: none; width: 168px; }
.kess-about-portrait img {
  display: block; width: 100%; border-radius: var(--kess-r);
  border: 1px solid var(--kess-border);
}
.kess-about-words { min-width: 0; flex: 1 1 auto; }
.kess-about-words .kess-about-prose { margin-top: 12px; }
.kess-about-by { margin-top: 14px; padding-left: 13px; border-left: 2px solid var(--kess-accent); }
.kess-about-by-name { display: block; font-size: calc(13.5px * var(--kess-fs-headings, 1)); font-weight: 650; color: var(--kess-ink); }
.kess-about-by-role { display: block; font-size: calc(12px * var(--kess-fs-body, 1)); color: var(--kess-ink-3); }
@media (max-width: 720px) {
  .kess-about-welcome { flex-direction: column; }
  .kess-about-portrait { width: 132px; }
}

/* one grid, three densities - a list of companies, a pair of statements, a set of values, a row of faces */
.kess-about-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); gap: 14px; align-items: start; }
.kess-about-grid.is-two { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; }
.kess-about-grid.is-people { grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 18px; }

.kess-about-panel {
  display: flex; flex-direction: column; gap: 7px; min-width: 0; height: 100%;
  padding: 16px; border-radius: var(--kess-r);
  background: var(--kess-surface); border: 1px solid var(--kess-border);
}
.kess-about-panel-title { margin: 0; font-size: calc(13.5px * var(--kess-fs-headings, 1)); font-weight: 650; color: var(--kess-ink); }
.kess-about-panel-note { font-size: calc(11.5px * var(--kess-fs-secondary, 1)); font-weight: 500; color: var(--kess-accent); }

/* a statement, which is a thing to read rather than a thing to scan - it gets the room to say so */
.kess-about-feature {
  display: flex; flex-direction: column; gap: 12px; min-width: 0; height: 100%;
  padding: 22px; border-radius: var(--kess-r);
  background: color-mix(in srgb, var(--kess-accent) 5%, var(--kess-surface));
  border: 1px solid var(--kess-accent-line);
}
.kess-about-feature img { max-height: 72px; max-width: 100%; align-self: flex-start; }
.kess-about-feature-title { margin: 0; font-size: calc(16px * var(--kess-fs-headings, 1)); font-weight: 680; letter-spacing: -.015em; color: var(--kess-ink); }

/* a value is a heading and a short list under a number, and the number is what makes the set read as one */
.kess-about-value {
  position: relative; display: flex; flex-direction: column; gap: 8px; min-width: 0; height: 100%;
  padding: 16px 16px 16px 17px; border-radius: var(--kess-r);
  background: var(--kess-surface); border: 1px solid var(--kess-border);
  border-top: 2px solid var(--kess-accent);
}
.kess-about-value-no {
  font-family: var(--kess-mono); font-size: calc(10.5px * var(--kess-fs-secondary, 1)); font-weight: 600; letter-spacing: .06em;
  color: var(--kess-accent);
}
.kess-about-value-title { margin: 0; font-size: calc(14px * var(--kess-fs-headings, 1)); font-weight: 680; letter-spacing: -.01em; color: var(--kess-ink); }
.kess-about-value-note { font-size: calc(12px * var(--kess-fs-body, 1)); line-height: 1.6; color: var(--kess-ink-3); }

/* a face, a name and what they do - no frame, because a card around a portrait reads as a record */
.kess-about-person { margin: 0; min-width: 0; text-align: center; }
.kess-about-person img {
  display: block; width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: var(--kess-r);
}
.kess-about-person figcaption { margin-top: 11px; }
.kess-about-person-name { display: block; font-size: calc(13.5px * var(--kess-fs-headings, 1)); font-weight: 650; color: var(--kess-ink); }
.kess-about-person-role { display: block; margin-top: 2px; font-size: calc(11.5px * var(--kess-fs-secondary, 1)); color: var(--kess-ink-3); }

.kess-player { position: fixed; inset: 0; display: flex; flex-direction: column; background: var(--kess-bg); }
.kess-player-head {
  flex: none; display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; background: var(--kess-surface); border-bottom: 1px solid var(--kess-border);
}
.kess-player-title { min-width: 0; font-size: calc(14px * var(--kess-fs-headings, 1)); font-weight: 650; letter-spacing: -.01em; }
.kess-player-frame { flex: 1 1 auto; position: relative; background: #000; }
.kess-player-frame > iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.kess-player-note {
  position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 10px;
  background: var(--kess-bg); color: var(--kess-ink-3); font-size: calc(12.5px * var(--kess-fs-body, 1));
}

/* ---- the login page ------------------------------------------------------------------------------------------------------
   Its own screen: there is no employee to draw a rail for. */

.kess-login { min-height: 100vh; display: grid; place-items: center; padding: 24px calc(24px) calc(24px + var(--kess-footer)); background: var(--kess-bg); }
.kess-login-card {
  width: 100%; max-width: 384px; padding: 28px;
  background: var(--kess-surface); border: 1px solid var(--kess-border);
  border-radius: var(--kess-r); box-shadow: var(--kess-lift);
}
.kess-login-brand { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 18px; }
.kess-login-title { font-size: calc(18px * var(--kess-fs-headings, 1)); font-weight: 650; letter-spacing: -.015em; text-align: center; }
.kess-login-sub { margin-bottom: 20px; text-align: center; font-size: calc(12.5px * var(--kess-fs-body, 1)); color: var(--kess-ink-3); }
.kess-login-foot { margin-top: 16px; text-align: center; font-size: calc(12px * var(--kess-fs-body, 1)); }

/* ---- helpers ---------------------------------------------------------------------------------------------------------------- */

.kess-muted { color: var(--kess-ink-3); }
.kess-soft { color: var(--kess-ink-2); }
.kess-strong { font-weight: 650; }
.kess-mono { font-family: var(--kess-mono); font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
.kess-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kess-nowrap { white-space: nowrap; }
.kess-grow { flex: 1 1 auto; min-width: 0; }
.kess-right { margin-left: auto; }
.kess-hidden { display: none !important; }
.kess-sep { height: 1px; margin: 12px 0; background: var(--kess-border); }
.kess-gap { display: flex; align-items: center; gap: 8px; }
.kess-gap.is-wrap { flex-wrap: wrap; }

/* ---- the punch console ------------------------------------------------------------------------

   The hero's top region. The component behind it is master's, untouched; this is only its clothes.
   Three cells that reflow on their own: where the employee stands, where the day is inside the
   office's punch window, and the button.
*/
.kess-punch-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  column-gap: 28px; row-gap: 16px; align-items: center;
}
.kess-punch-cell { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.kess-punch-cell.is-action { align-items: flex-end; justify-content: center; }

.kess-punch-eyebrow {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-family: var(--kess-mono);
  font-size: calc(10px * var(--kess-fs-labels, 1)); font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  color: var(--kess-ink-3);
}
.kess-punch-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--kess-ink-3); }
.kess-punch-eyebrow.is-on { color: var(--kess-success); }
.kess-punch-eyebrow.is-on .kess-punch-dot { background: var(--kess-live); box-shadow: 0 0 0 4px var(--kess-live-halo); }

.kess-punch-clockrow { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.kess-punch-clock {
  font-family: var(--kess-mono);
  font-size: calc(44px * var(--kess-fs-figures, 1)); font-weight: 600; line-height: .9; letter-spacing: -.03em;
  color: var(--kess-ink); font-variant-numeric: tabular-nums;
}
.kess-punch-said { display: flex; flex-direction: column; gap: 2px; padding-bottom: 3px; min-width: 0; }
.kess-punch-state { font-size: calc(12px * var(--kess-fs-body, 1)); font-weight: 600; line-height: 1.2; color: var(--kess-ink); }
.kess-punch-sub { font-size: calc(11.5px * var(--kess-fs-secondary, 1)); line-height: 1.3; color: var(--kess-ink-3); }
.kess-punch-meta { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }

.kess-punch-notice {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: calc(11.5px * var(--kess-fs-secondary, 1)); line-height: 1.35; color: var(--kess-danger);
  text-align: left;
}

/* The reason the card is there, so it is the one button that carries the accent at full weight -
   but as glass rather than as a slab: a tint over whatever is behind it, a lit top edge, and a blur.
   Everything in it is mixed from the accent, so it follows the installation's colour like the rest. */
.kess-punch-btn {
  height: auto; padding: 13px 20px;
  font-size: calc(13px * var(--kess-fs-body, 1)); font-weight: 600;
  border-radius: var(--kess-r-md);
  color: var(--kess-accent);
  background: color-mix(in srgb, var(--kess-accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--kess-accent) 30%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  backdrop-filter: blur(10px) saturate(150%);
  box-shadow: inset 0 1px 0 var(--kess-glass-hi), 0 1px 2px rgba(23, 26, 31, .06);
}
.kess-punch-btn:hover:not(:disabled) {
  color: var(--kess-accent);
  background: color-mix(in srgb, var(--kess-accent) 22%, transparent);
  border-color: color-mix(in srgb, var(--kess-accent) 46%, transparent);
}
.kess-punch-btn:disabled,
.kess-punch-btn:disabled:hover {
  color: var(--kess-ink-3);
  background: color-mix(in srgb, var(--kess-ink-3) 10%, transparent);
  border-color: color-mix(in srgb, var(--kess-ink-3) 22%, transparent);
}
/* Solid where the rest is tinted, so the marker still reads against its own button. */
.kess-punch-square { flex: none; width: 8px; height: 8px; border-radius: 2px; background: var(--kess-accent); }
.kess-punch-btn:disabled .kess-punch-square { background: var(--kess-ink-3); }
.kess-punch-maplink { font-size: calc(11px * var(--kess-fs-secondary, 1)); }

.kess-punch-map { margin-top: 14px; border-radius: var(--kess-r-md); overflow: hidden; border: 1px solid var(--kess-border); }

@media (max-width: 720px) {
  .kess-punch-cell.is-action { align-items: stretch; }
  .kess-punch-btn { width: 100%; }
  .kess-punch-maplink { text-align: center; }
}

/* ---- borrowed bootstrap, still worn by the profile form ----------------------------------------
   These dressed the punch card until it was rewritten in `kess-` classes. `sections/personal` still
   mounts KFormBuilder's markup inside `.kess-guest`, so they stay. */

.kess-guest .card-header.bg-primary {
  background-color: var(--kess-sunk) !important;
  color: var(--kess-ink) !important;
  border-bottom: 1px solid var(--kess-border) !important;
  padding: 9px 12px !important;
}
.kess-guest .card-header.bg-primary .text-white { color: var(--kess-ink) !important; }
.kess-guest .card-header.bg-primary .fw-semibold { font-family: var(--kess-mono); font-size: calc(11.5px * var(--kess-fs-secondary, 1)); }
.kess-guest .card-header.bg-primary .font-monospace {
  font-family: var(--kess-mono) !important; font-size: calc(17px * var(--kess-fs-figures, 1)); font-weight: 600; letter-spacing: -.02em;
}
.kess-guest .alert-success {
  background: var(--kess-success-wash) !important;
  box-shadow: inset 2px 0 0 var(--kess-success);
  border-radius: var(--kess-r-xs) !important;
}
.kess-guest .alert-success small,
.kess-guest .alert-success .text-muted { color: var(--kess-success) !important; }
.kess-guest .btn-success {
  font-family: var(--kess-mono); letter-spacing: .1em; font-weight: 600 !important;
  border-radius: var(--kess-r-xs) !important;
}
.kess-guest .btn-lg { height: 42px; padding: 0 16px !important; font-size: calc(12.5px * var(--kess-fs-body, 1)) !important; }
.kess-guest .bg-light {
  border: 1px solid var(--kess-border);
  border-radius: var(--kess-r-xs);
  padding: 9px !important;
}
.kess-guest .bg-light small { font-family: var(--kess-mono); font-size: calc(13px * var(--kess-fs-body, 1)); color: var(--kess-ink) !important; }
.kess-guest .bg-light .fw-bold {
  font-family: var(--kess-mono); font-size: calc(9px * var(--kess-fs-labels, 1)); letter-spacing: .15em; text-transform: uppercase;
}

/* ---- responsive ----------------------------------------------------------------------------------------------------------------
   Below the breakpoint the rail stops being a rail: it is a drawer, opened by the topbar's hamburger,
   and it is always at its open width because there is no pointer to hover with. */
@media (max-width: 992px) {

  .kess-rail {
    width: var(--kess-rail-open);
    transform: translateX(-100%);
    transition: transform .2s cubic-bezier(.4, 0, .2, 1);
    box-shadow: var(--kess-lift);
  }
  .kess-rail.is-open { transform: translateX(0); }
  .kess-rail .kess-rail-wide { opacity: 1; }
  .kess-rail .kess-navgroup + .kess-navgroup { border-top-color: transparent; }
  .kess-root:not(.is-rail-open) .kess-navgroup-title { height: 15px; margin: 0 0 4px; }
  .kess-root:not(.is-rail-open) .kess-railfoot { display: flex; }

  .kess-body,
  .kess-root.is-rail-open .kess-rail ~ .kess-body { margin-left: 0; transition: none; }
  .kess-rail:has(:focus-visible) ~ .kess-body { margin-left: 0; transition: none; }

  .kess-body .kess-footer,
  .kess-root.is-rail-open .kess-rail ~ .kess-body .kess-footer { left: 0; transition: none; }
  .kess-rail:has(:focus-visible) ~ .kess-body .kess-footer { left: 0; transition: none; }

  .kess-hamburger { display: flex; }
  .kess-railbtn { display: none; }
  .kess-content { padding: 12px; }

  .kess-scrim { display: block; position: fixed; inset: 0; z-index: 35; background: rgba(16, 22, 33, .45); }

}

.kess-scrim { display: none; }

@media (max-width: 576px) {
  .kess-me-name { display: none; }
  .kess-toasts { left: 12px; right: 12px; bottom: calc(12px + var(--kess-footer)); max-width: none; }
  .kess-defs { grid-template-columns: minmax(0, 1fr); }
}

/* ---- motion --------------------------------------------------------------------------------------
   Everything that moves here is an easing on a state change, so there is nothing to keep. */
@media (prefers-reduced-motion: reduce) {
  :is(.kess-root, .kess-portal) *,
  :is(.kess-root, .kess-portal) *::before,
  :is(.kess-root, .kess-portal) *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- print ---------------------------------------------------------------------------------------------------------------------- */

@media print {
  .kess-rail, .kess-topbar, .kess-toasts, .kess-progress, .kess-btnbar, .kess-footer { display: none !important; }
  .kess-content { padding-bottom: 16px; }
  .kess-body { margin-left: 0; }
  .kess-card { break-inside: avoid; box-shadow: none; }
}
