/* Master SECURITY theme — shared Master Series design system (navy + green,
   Samsung Sharp Sans) with the Master Security "command console" component style:
   crisper corners, hairline borders instead of soft shadows, left-accent status
   cards, dot-indicator chips and uppercase micro-labels. */

:root {
    /* Shared Master Series palette — identical across Master Service / Wash / Security */
    --ms-navy-950: #081b33;
    --ms-navy-900: #0c2340;
    --ms-navy-800: #123156;
    --ms-navy-700: #17406f;
    --ms-navy-600: #1d4f88;
    --ms-navy-500: #2360a5;
    --ms-navy-100: #dbe7f5;
    --ms-navy-50:  #eef4fb;
    --ms-green-900: #0d3f12;
    --ms-green-800: #14541b;
    --ms-green-700: #1b6a24;
    --ms-green-600: #23842e;
    --ms-green-500: #2e9e3a;
    --ms-green-400: #4ab653;
    --ms-green-100: #ddf2df;
    --ms-green-50:  #effaf0;
    --ms-ink: #13202f;
    --ms-muted: #5d6b7c;
    --ms-line: #dde4ec;
    --ms-bg: #f4f7fa;
    --ms-card: #ffffff;
    --ms-danger: #c62828;
    --ms-warn: #e65100;
    --ms-radius: 14px;
    --ms-shadow: 0 2px 14px rgba(12,35,64,.08);
    --ms-font: "Samsung Sharp Sans", "Segoe UI", Arial, sans-serif;

    /* Master Security aliases + product-specific tuning */
    --msec-radius: 10px;        /* crisper than the siblings' 14px */
    --msec-radius-sm: 8px;
    --msec-amber: #b45309;
    --msec-amber-bg: #fef3c7;
    --msec-red-bg: #fde8e8;
    --msec-rail-w: 84px;
    --msec-cmdbar-h: 58px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
    margin: 0;
    font-family: var(--ms-font);
    color: var(--ms-ink);
    background: var(--ms-bg);
    font-size: 15.5px;
    line-height: 1.55;
}
h1, h2, h3, h4 { color: var(--ms-navy-900); line-height: 1.25; margin: 0 0 12px; }
h1 { font-size: 26px; font-weight: 800; }
h2 { font-size: 20px; font-weight: 800; }
h3 { font-size: 17px; font-weight: 700; }
p { margin: 0 0 14px; }
a { color: var(--ms-green-700); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; }

.ic { width: 22px; height: 22px; flex: 0 0 auto; }
.ic-sm { width: 17px; height: 17px; flex: 0 0 auto; }

/* Micro-label: the Master Security uppercase eyebrow used on cards, tables, rails */
.micro {
    font-size: 11px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--ms-muted);
}

/* ---------------------------------------------------------------- buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: var(--ms-navy-800);
    color: #fff;
    border: 1.5px solid transparent;
    border-radius: var(--msec-radius-sm);
    padding: 11px 20px;
    font-family: var(--ms-font);
    font-size: 14.5px;
    font-weight: 700;
    min-height: 44px;
    cursor: pointer;
    text-decoration: none;
    transition: background .15s, border-color .15s, color .15s;
}
.btn:hover { background: var(--ms-navy-900); text-decoration: none; }
/* The primary action carries a glaze: a polished face that is brightest along the
   top edge and deepens towards the foot, with a hairline of light on the top
   border and a shadow line on the bottom one. The light NEVER goes above the
   green the button has always been (--ms-green-600 is the top stop and nothing
   in the glaze is lighter), so the white label keeps its contrast — the face
   under the text is green-700 or darker, which measures better than the flat
   green it replaces. The shine that travels across on hover is in the motion
   section at the foot of this file. */
.btn-green {
    position: relative;
    overflow: hidden;
    background-color: var(--ms-green-700);
    background-image: linear-gradient(180deg,
        var(--ms-green-600) 0%,
        var(--ms-green-700) 32%,
        var(--ms-green-800) 100%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.22), inset 0 -1px 0 rgba(0,0,0,.18);
}
.btn-green:hover {
    background-color: var(--ms-green-800);
    background-image: linear-gradient(180deg,
        var(--ms-green-700) 0%,
        var(--ms-green-800) 32%,
        var(--ms-green-900) 100%);
}
.btn-outline { background: transparent; border-color: var(--ms-navy-800); color: var(--ms-navy-800); }
.btn-outline:hover { background: var(--ms-navy-50); }
.btn-ghost { background: transparent; color: var(--ms-navy-800); }
.btn-ghost:hover { background: var(--ms-navy-50); }
.btn-danger { background: var(--ms-danger); }
.btn-danger:hover { background: #a51f1f; }
.btn-sm { padding: 7px 13px; min-height: 36px; font-size: 13.5px; border-radius: 7px; }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .55; cursor: not-allowed; }

/* ---------------------------------------------------------------- cards
   Signature: hairline border + optional 3px status accent on the LEFT edge.
   (No soft drop shadows — that is the siblings' look.) */
.card {
    background: var(--ms-card);
    border: 1px solid var(--ms-line);
    border-radius: var(--msec-radius);
    padding: 20px;
    margin-bottom: 16px;
}
.card:hover { border-color: #c9d4e2; }
.card-accent { border-left: 3px solid var(--ms-green-600); }
.card-navy { border-left: 3px solid var(--ms-navy-700); }
.card-warn { border-left: 3px solid var(--msec-amber); }
.card-danger { border-left: 3px solid var(--ms-danger); }
.card-title {
    display: flex;
    align-items: center;
    gap: 9px;
    font-weight: 800;
    color: var(--ms-navy-900);
    font-size: 16px;
    margin: 0 0 14px;
}
.card-title .ic { color: var(--ms-green-600); }
.card-sub { color: var(--ms-muted); font-size: 13.5px; margin-top: -10px; margin-bottom: 14px; }

/* Dark command panel (dashboard hero surfaces) */
.panel-dark {
    background: linear-gradient(160deg, var(--ms-navy-950), var(--ms-navy-800));
    color: #fff;
    border: 1px solid var(--ms-navy-700);
    border-radius: var(--msec-radius);
    padding: 20px;
    margin-bottom: 16px;
}
.panel-dark h2, .panel-dark h3 { color: #fff; }
.panel-dark .micro { color: rgba(255,255,255,.55); }
.panel-dark a { color: var(--ms-green-400); }

/* ---------------------------------------------------------------- board tiles (KPIs) */
.board { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 12px; margin-bottom: 16px; }
/* Every tile in a row is already the same height (the grid stretches them), so the
   number is anchored to the FOOT of the tile rather than left to float wherever its
   label happens to end. Without this a label that wraps to two or three lines pushed
   its own number down while its neighbours' stayed up, and a row of tiles read as a
   ragged staircase. */
.tile {
    background: var(--ms-card);
    border: 1px solid var(--ms-line);
    border-radius: var(--msec-radius);
    padding: 14px 16px;
    position: relative;
    display: flex;
    flex-direction: column;
}
.tile .tile-num { font-size: 27px; font-weight: 800; color: var(--ms-navy-900); line-height: 1.15; margin-top: auto; }
.tile .tile-num.ok { color: var(--ms-green-700); }
.tile .tile-num.warn { color: var(--msec-amber); }
.tile .tile-num.bad { color: var(--ms-danger); }
/* padding-right keeps a wrapping label clear of the corner icon */
.tile .micro { display: block; margin-bottom: 4px; padding-right: 30px; }
.tile .ic { position: absolute; top: 14px; right: 14px; color: var(--ms-navy-100); width: 26px; height: 26px; }
/* A tile that is a link is laid out by .tile above, so it must not go back to block */
a.tile { text-decoration: none; }
a.tile:hover { border-color: var(--ms-green-500); text-decoration: none; }

/* ---------------------------------------------------------------- chips (status with dot) */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border-radius: 7px;
    padding: 4px 10px;
    font-size: 12.5px;
    font-weight: 700;
    background: var(--ms-navy-50);
    color: var(--ms-navy-800);
    white-space: nowrap;
}
.chip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--ms-navy-500); flex: 0 0 auto; }
.chip-ok { background: var(--ms-green-50); color: var(--ms-green-800); }
.chip-ok::before { background: var(--ms-green-500); }
.chip-warn, .chip-med { background: var(--msec-amber-bg); color: var(--msec-amber); }
.chip-warn::before, .chip-med::before { background: var(--msec-amber); }
.chip-bad, .chip-high, .chip-crit { background: var(--msec-red-bg); color: var(--ms-danger); }
.chip-bad::before, .chip-high::before, .chip-crit::before { background: var(--ms-danger); }
.chip-low { background: var(--ms-navy-50); color: var(--ms-navy-700); }
.chip-muted { background: #eef1f5; color: var(--ms-muted); }
.chip-muted::before { background: #9aa7b5; }
.chip-crit::before { animation: msec-pulse 1.4s ease-in-out infinite; }

/* Live indicator dot */
.live-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--ms-green-500); animation: msec-pulse 1.8s ease-in-out infinite; }
@keyframes msec-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(46,158,58,.45); }
    50% { box-shadow: 0 0 0 6px rgba(46,158,58,0); }
}
@media (prefers-reduced-motion: reduce) {
    .live-dot, .chip-crit::before { animation: none; }
}

/* ---------------------------------------------------------------- forms */
.field { margin-bottom: 15px; }
.field label { display: block; font-weight: 700; font-size: 13.5px; margin-bottom: 6px; color: var(--ms-navy-900); }
/* .hint works standalone too (status lines, inline explanations), not only inside .field */
.hint, .field .hint { display: block; font-size: 12.5px; color: var(--ms-muted); margin-top: 5px; line-height: 1.45; }
/* ---------------------------------------------------------------- password fields
   The reveal button sits INSIDE the box, so it reads as part of the field rather than
   a stray control next to it. The input gets right padding to match, otherwise a long
   password runs underneath the eye. .pw-wrap is a block so it occupies exactly the box
   the input used to, and nothing in the layout shifts when the script wraps it.
   Note the stylesheet must treat input[type=text] and input[type=password] identically
   (it does, in the rule below): revealing swaps the type, and any difference between
   the two would make the box jump while somebody is mid-word. */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { padding-right: 46px !important; }
.pw-eye {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--ms-muted);
    cursor: pointer;
}
.pw-eye:hover { background: var(--ms-navy-50); color: var(--ms-navy-800); }
.pw-eye:focus-visible { outline: 2px solid var(--ms-green-600); outline-offset: 1px; }
.pw-eye[aria-pressed="true"] { color: var(--ms-green-700); }

.pw-suggest {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    margin: -8px 0 15px;
}
.pw-suggest-btn {
    border: 0;
    background: none;
    padding: 0;
    font-family: var(--ms-font);
    font-size: 13px;
    font-weight: 700;
    color: var(--ms-green-700);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}
.pw-suggest-btn:hover { color: var(--ms-green-800); }
.pw-suggest-btn:focus-visible { outline: 2px solid var(--ms-green-600); outline-offset: 2px; border-radius: 3px; }
.pw-suggest-note { font-size: 12.5px; color: var(--ms-muted); font-weight: 600; }

/* The gatehouse device draws its own oversized inputs, so the eye is scaled to match
   the fat-finger target size used everywhere on that screen. */
.dev-in + .pw-eye, .pw-wrap .dev-in + .pw-eye { width: 42px; height: 42px; right: 8px; color: #cfe0f2; }
.pw-wrap .dev-in { padding-right: 56px !important; }
.dev-in + .pw-eye:hover { background: rgba(255,255,255,.1); color: #fff; }

.field input[type=text], .field input[type=email], .field input[type=password],
.field input[type=tel], .field input[type=number], .field input[type=date],
.field input[type=time], .field input[type=datetime-local], .field input[type=month],
.field input[type=week], .field input[type=search], .field select, .field textarea {
    width: 100%;
    border: 1.5px solid var(--ms-line);
    border-radius: var(--msec-radius-sm);
    padding: 11px 13px;
    font-family: var(--ms-font);
    font-size: 15px;
    color: var(--ms-ink);
    background: #fff;
    min-height: 44px;
}
/* Text boxes start tall enough to read a paragraph without scrolling, and grow as
   you type (assets/js/app.js). Never smaller than this. */
.field textarea, textarea {
    min-height: 130px;
    resize: vertical;
    line-height: 1.55;
    overflow-y: hidden;
}
.field textarea.tall, textarea.tall { min-height: 220px; }
.field textarea.short, textarea.short { min-height: 88px; }
.field input:focus, .field select:focus, .field textarea:focus {
    outline: none;
    border-color: var(--ms-green-500);
    box-shadow: 0 0 0 3px var(--ms-green-100);
}
.field input[aria-invalid=true], .field .invalid { border-color: var(--ms-danger); }
/* A select that is NOT wrapped in a .field — a filter standing in a .toolbar, a
   status picker in a table row — used to fall through to the browser's own 19px
   grey dropdown, which looks nothing like the controls beside it. This gives it
   the same border, radius, height and focus ring as the search box, so a toolbar
   row lines up. It is deliberately the weakest rule in the file: a plain element
   selector, so the .field block above and any page's own inline style both still
   win and a select inside a .field is never styled twice. Width is the one thing
   NOT set — a filter sizes to its longest option, it does not stretch across the
   page — and max-width keeps a long option from widening a phone. Appearance is
   left alone, exactly as in .field, so the browser keeps drawing its own chevron
   over the right-hand padding. */
select {
    border: 1.5px solid var(--ms-line);
    border-radius: var(--msec-radius-sm);
    padding: 11px 13px;
    font-family: var(--ms-font);
    font-size: 15px;
    color: var(--ms-ink);
    background: #fff;
    min-height: 44px;
    max-width: 100%;
    transition: border-color .15s, box-shadow .15s;
}
select:focus { outline: none; border-color: var(--ms-green-500); box-shadow: 0 0 0 3px var(--ms-green-100); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }
.check-row { display: flex; gap: 10px; align-items: flex-start; font-size: 14px; margin-bottom: 12px; }
.check-row input { width: 19px; height: 19px; margin-top: 2px; accent-color: var(--ms-green-600); }

/* The hidden attribute must always win. Any component that sets its own display
   (.alert is flex, .toolbar is flex, a grid card is grid) would otherwise override the
   browser's default and show a box the script deliberately hid, which is exactly what
   happened to the resident's "someone is at the gate" line. */
[hidden] { display: none !important; }

/* ---------------------------------------------------------------- tables */
.table-wrap { overflow-x: auto; background: var(--ms-card); border: 1px solid var(--ms-line); border-radius: var(--msec-radius); margin-bottom: 16px; }
table.data { width: 100%; border-collapse: collapse; font-size: 14.5px; }
table.data th {
    text-align: left;
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--ms-muted);
    background: #f8fafc;
    padding: 11px 14px;
    border-bottom: 1px solid var(--ms-line);
    white-space: nowrap;
}
table.data td { padding: 12px 14px; border-bottom: 1px solid #edf1f6; vertical-align: middle; }
table.data tr:last-child td { border-bottom: 0; }
table.data tr:hover td { background: #fafcfe; }
table.data td.num { font-variant-numeric: tabular-nums; }
.row-link { cursor: pointer; }
/* On phones let the table keep readable column widths and scroll sideways inside
   .table-wrap, rather than squeezing every cell into a stack of single words. */
@media (max-width: 700px) {
    table.data { min-width: 620px; }
    table.data th, table.data td { padding: 11px 12px; }
    .table-wrap { position: relative; }
}

/* A panel that lists live work grows with the work. Five open emergencies and a
   handful of expiring credentials and the command page is suddenly three screens
   tall, with the next panel pushed below the fold and the whole page a different
   height every time it loads. .table-scroll fixes a panel's height and moves the
   rows inside it instead, so the page stays put whatever the day is doing. The
   header row stays visible while the rows scroll under it. */
.table-scroll { max-height: 332px; overflow-y: auto; overscroll-behavior: contain; }
.table-scroll table.data thead th { position: sticky; top: 0; z-index: 1; }
@media (max-width: 700px) { .table-scroll { max-height: 296px; } }

/* A quiet scrollbar: visible enough to say "there is more below", not a grey slab
   down the side of every card. */
.table-scroll { scrollbar-width: thin; scrollbar-color: #cbd5e1 transparent; }
.table-scroll::-webkit-scrollbar { width: 9px; }
.table-scroll::-webkit-scrollbar-track { background: transparent; }
.table-scroll::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 999px; border: 2px solid var(--ms-card); }
.table-scroll::-webkit-scrollbar-thumb:hover { background: #94a3b8; }

/* On paper there is no scrolling, so a capped panel prints in full. */
@media print { .table-scroll { max-height: none; overflow: visible; } }

/* ---------------------------------------------------------------- alerts + flashes */
.alert {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    border-radius: var(--msec-radius-sm);
    padding: 12px 15px;
    font-size: 14.5px;
    font-weight: 600;
    margin-bottom: 14px;
    border: 1px solid transparent;
}
.alert .ic { width: 19px; height: 19px; margin-top: 1px; }
.alert-success { background: var(--ms-green-50); color: var(--ms-green-800); border-color: var(--ms-green-100); }
.alert-error { background: var(--msec-red-bg); color: var(--ms-danger); border-color: #f6c8c8; }
.alert-info { background: var(--ms-navy-50); color: var(--ms-navy-800); border-color: var(--ms-navy-100); }
.alert-warn { background: var(--msec-amber-bg); color: var(--msec-amber); border-color: #fde3a7; }

/* ---------------------------------------------------------------- modal */
.modal-back {
    position: fixed; inset: 0;
    background: rgba(8,27,51,.55);
    display: none;
    align-items: center; justify-content: center;
    z-index: 300;
    padding: 18px;
}
.modal-back.open { display: flex; }
.modal {
    background: #fff;
    border-radius: var(--msec-radius);
    border-top: 3px solid var(--ms-green-600);
    padding: 24px;
    max-width: 560px;
    width: 100%;
    max-height: 88vh;
    overflow-y: auto;
}

/* ---------------------------------------------------------------- misc */
.empty {
    text-align: center;
    color: var(--ms-muted);
    padding: 38px 18px;
}
.empty .ic { width: 40px; height: 40px; color: var(--ms-navy-100); margin-bottom: 8px; }
.toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 16px; }
.toolbar .spacer { flex: 1; }
.split { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
@media (max-width: 900px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }
/* A grid or flex child defaults to min-width:auto, so on a phone the 620px table inside
   a card inside a grid forced the page to 680px wide and it panned sideways (Command,
   Profile, the portal). With min-width:0 the child may shrink and .table-wrap does what
   it is for: the TABLE scrolls inside its box, the PAGE stays the width of the phone. */
.grid-2 > *, .grid-3 > *, .board > *, .card, .table-wrap { min-width: 0; }
/* align-self keeps the chip hugging its own words: as a child of the flex column
   above it would otherwise be stretched to the full width of the tile. */
.tile .chip { white-space: normal; max-width: 100%; align-self: flex-start; }
.muted { color: var(--ms-muted); }
.small { font-size: 13px; }
.nowrap { white-space: nowrap; }
.mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; }
.avatar {
    width: 38px; height: 38px; border-radius: 50%;
    background: var(--ms-navy-800); color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 800; font-size: 14px; flex: 0 0 auto;
}
.qr-chip { background: #fff; border: 1px solid var(--ms-line); border-radius: var(--msec-radius); padding: 12px; display: inline-block; }
.suite-line { text-align: center; font-size: 12px; color: var(--ms-muted); padding: 18px 0 8px; }
.suite-line a { color: var(--ms-green-700); }
/* The registration numbers under the suite line: the smallest print in the app. */
.suite-reg { text-align: center; font-size: 10.5px; letter-spacing: .02em; color: var(--ms-muted); opacity: .75; padding: 0 0 10px; }

/* Timeline (incident / case history) */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { position: relative; padding: 0 0 18px 26px; }
.timeline li::before {
    content: ""; position: absolute; left: 5px; top: 6px;
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--ms-green-500);
}
.timeline li.tl-navy::before { background: var(--ms-navy-500); }
.timeline li.tl-red::before { background: var(--ms-danger); }
.timeline li::after {
    content: ""; position: absolute; left: 8.5px; top: 17px; bottom: -2px;
    width: 2px; background: var(--ms-line);
}
.timeline li:last-child::after { display: none; }
.timeline .tl-time { font-size: 12px; color: var(--ms-muted); }

/* ---------------------------------------------------------------- search box
   One search control for the whole system: same height, radius and focus ring as
   every other input, with the magnifier inside it. */
.search-box { position: relative; display: inline-flex; align-items: center; min-width: 260px; flex: 0 1 340px; }
.search-box .ic, .search-box .ic-sm {
    position: absolute; left: 12px;
    color: var(--ms-muted);
    pointer-events: none;
    width: 18px; height: 18px;
}
.search-box input[type=search], .search-box input[type=text] {
    width: 100%;
    border: 1.5px solid var(--ms-line);
    border-radius: var(--msec-radius-sm);
    padding: 11px 13px 11px 38px;
    font-family: var(--ms-font);
    font-size: 15px;
    color: var(--ms-ink);
    background: #fff;
    min-height: 44px;
    transition: border-color .15s, box-shadow .15s;
}
.search-box input:focus {
    outline: none;
    border-color: var(--ms-green-500);
    box-shadow: 0 0 0 3px var(--ms-green-100);
}
.search-box input::-webkit-search-cancel-button { cursor: pointer; }
@media (max-width: 700px) { .search-box { flex: 1 1 100%; min-width: 0; } }

/* ---------------------------------------------------------------- address + hours */
.addr-set, .hours-set {
    border: 1px solid var(--ms-line);
    border-radius: var(--msec-radius);
    padding: 16px 18px 6px;
    margin: 0 0 16px;
    background: #fcfdfe;
}
.addr-legend {
    padding: 0 8px;
    font-size: 11px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--ms-navy-800);
}
.addr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
.addr-grid .addr-line1, .addr-grid .addr-line2 { grid-column: 1 / -1; }
@media (max-width: 640px) { .addr-grid { grid-template-columns: 1fr; } }

.hours-modes { display: flex; flex-wrap: wrap; gap: 10px 20px; margin-bottom: 14px; }
.hours-mode, .hours-pick { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 600; cursor: pointer; }
.hours-mode input, .hours-pick input { width: 17px; height: 17px; accent-color: var(--ms-green-600); }
.hours-row {
    display: grid;
    grid-template-columns: 110px auto;
    gap: 6px 14px;
    align-items: center;
    padding: 10px 0;
    border-top: 1px solid var(--ms-line);
}
.hours-row:first-child { border-top: 0; }
.hours-day { font-weight: 700; font-size: 14px; color: var(--ms-navy-900); }
.hours-state { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.hours-times { grid-column: 2; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; padding-bottom: 4px; }
.hours-second { display: flex; gap: 10px; align-items: flex-end; }
.hours-t { display: flex; flex-direction: column; gap: 3px; }
.hours-t input[type=time] {
    border: 1.5px solid var(--ms-line);
    border-radius: var(--msec-radius-sm);
    padding: 8px 10px;
    font-family: var(--ms-font);
    font-size: 14.5px;
    min-height: 40px;
    background: #fff;
}
.hours-t input[type=time]:focus { outline: none; border-color: var(--ms-green-500); box-shadow: 0 0 0 3px var(--ms-green-100); }
@media (max-width: 700px) {
    .hours-row { grid-template-columns: 1fr; }
    .hours-times { grid-column: 1; }
}

/* ---------------------------------------------------------------- motion
   Movement is a cue, never decoration: things lift slightly when you can click
   them, new panels settle in, and anything live keeps a slow pulse. All of it is
   short, and all of it is switched off for prefers-reduced-motion. */
.card, .tile, .feat, .duty-btn, .btn, .chip, .sub-pills a, .rail a, .cmd-chip, .price-card {
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease, background-color .15s ease, color .15s ease;
}
.card:hover { border-color: #c6d2e1; box-shadow: 0 6px 20px rgba(12,35,64,.07); }
a.tile:hover, .duty-btn:hover, .feat:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 26px rgba(12,35,64,.12);
    border-color: var(--ms-green-500);
}
.tile:hover { box-shadow: 0 6px 18px rgba(12,35,64,.08); }
.btn:not([disabled]):hover { transform: translateY(-1px); }
.btn:not([disabled]):active { transform: translateY(0); }
.rail a:hover { transform: translateX(2px); }
.sub-pills a:hover { transform: translateY(-1px); }
table.data tbody tr { transition: background-color .13s ease; }
tr.row-link:hover td { background: var(--ms-navy-50); }

/* Panels settle in on load, staggered so the eye follows the page down */
@keyframes msec-rise { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
.card, .tile, .panel-dark, .duty-hero, .table-wrap { animation: msec-rise .34s ease both; }
/* A transformed element becomes the containing block for its position:fixed children,
   so a card that is mid-rise (or holding the animation's first frame) traps a modal
   inside its own box: the backdrop stops being viewport-sized, max-height:88vh never
   engages, and the foot of the dialog — the Save button — is simply cut off with no
   way to scroll to it. A container that holds a dialog therefore does not animate. */
.card:has(.modal-back), .tile:has(.modal-back), .panel-dark:has(.modal-back),
.duty-hero:has(.modal-back), .table-wrap:has(.modal-back) { animation: none; }
.board .tile:nth-child(2) { animation-delay: .03s; }
.board .tile:nth-child(3) { animation-delay: .06s; }
.board .tile:nth-child(4) { animation-delay: .09s; }
.board .tile:nth-child(5) { animation-delay: .12s; }
.board .tile:nth-child(6) { animation-delay: .15s; }
.board .tile:nth-child(7) { animation-delay: .18s; }
.board .tile:nth-child(8) { animation-delay: .21s; }

/* A number that has just changed gets one quiet nudge */
@keyframes msec-count { 0% { transform: translateY(4px); opacity: .55; } 100% { transform: none; opacity: 1; } }
.tile-num { display: inline-block; animation: msec-count .45s ease both; }

/* Alerts slide in rather than appearing from nowhere */
@keyframes msec-slide { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.alert { animation: msec-slide .28s ease both; }

/* Modals fade the backdrop and lift the panel */
@keyframes msec-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes msec-pop { from { opacity: 0; transform: translateY(12px) scale(.985); } to { opacity: 1; transform: none; } }
.modal-back.open { animation: msec-fade .18s ease both; }
.modal-back.open .modal { animation: msec-pop .24s cubic-bezier(.2,.8,.3,1) both; }

/* The shine on the primary action: one soft band of light crosses the face when
   you point at the button or reach it with the keyboard, then waits off the left
   edge again. It travels once, it never loops, and it is kept faint enough that
   the white label stays legible while it passes over. Nothing else moves — the
   resting glaze above is a still gradient. Works the same on a green button that
   holds an icon, a small one, a full-width one, and one standing on a navy band;
   a disabled button never lights up. */
.btn-green::after {
    content: "";
    position: absolute;
    top: -1px; bottom: -1px;
    left: -55%;
    width: 40%;
    background: linear-gradient(90deg,
        rgba(255,255,255,0) 0%,
        rgba(255,255,255,.14) 50%,
        rgba(255,255,255,0) 100%);
    transform: translateX(0) skewX(-18deg);
    /* No transition at rest, so when the pointer leaves the band returns to its
       parked position instantly (both ends are off the button, so nothing is
       seen) rather than swinging back across the face a second time. */
    transition: transform 0s;
    pointer-events: none;
}
.btn-green:not([disabled]):hover::after,
.btn-green:not([disabled]):focus-visible::after {
    transform: translateX(430%) skewX(-18deg);
    transition: transform .62s cubic-bezier(.3,.72,.32,1);
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
    a.tile:hover, .duty-btn:hover, .feat:hover, .btn:hover, .rail a:hover, .sub-pills a:hover { transform: none; }
    /* Keep the still glaze, drop the sweep entirely: the band stays parked off
       the edge instead of snapping across in a single frame. */
    .btn-green:not([disabled]):hover::after,
    .btn-green:not([disabled]):focus-visible::after { transform: translateX(0) skewX(-18deg); }
}

/* Print */
@media print {
    body { background: #fff; }
    .no-print { display: none !important; }
    .card, .tile, .table-wrap, .alert, .panel-dark, .duty-hero { animation: none !important; }
}
