:root{
  --gl-bg:#0f172a; --gl-panel:#ffffff; --gl-ink:#1e293b;
  --gl-accent:#2563eb; --gl-line:#e2e8f0;
}
.gl-body{background:#f1f5f9;color:var(--gl-ink);}
.gl-navbar{background:var(--gl-bg);}
.gl-navbar .navbar-brand,.gl-navbar a{color:#fff;}
.gl-sub{color:#60a5fa;font-weight:600;}
.gl-userchip{color:#cbd5e1;font-size:.9rem;}
.gl-role{display:inline-block;margin-left:.4rem;padding:.1rem .45rem;border-radius:6px;
  background:#1e293b;color:#93c5fd;font-size:.72rem;}
.gl-card{background:var(--gl-panel);border:1px solid var(--gl-line);border-radius:14px;
  padding:1.1rem 1.25rem;box-shadow:0 1px 2px rgba(15,23,42,.04);}
.gl-logo{font-size:1.4rem;font-weight:700;}
.gl-tabs .nav-link{background:#e2e8f0;color:#334155;}
.gl-tabs .nav-link.active{background:var(--gl-accent);color:#fff;}
.gl-cardinput{letter-spacing:.12em;}
.gl-stat{background:#fff;border:1px solid var(--gl-line);border-radius:14px;padding:.85rem 1rem;text-align:center;}
.gl-stat-n{font-size:1.6rem;font-weight:700;line-height:1;}
.gl-stat-l{font-size:.72rem;color:#64748b;text-transform:uppercase;letter-spacing:.04em;margin-top:.25rem;}
.gl-warn .gl-stat-n{color:#d97706;} .gl-danger .gl-stat-n{color:#dc2626;}
.gl-footer{margin-top:auto;padding:.9rem 1rem;text-align:center;color:#94a3b8;
  font-size:.78rem;border-top:1px solid var(--gl-line);background:#fff;}
.gl-ver{color:#2563eb;font-weight:600;}
.gl-foot-sep{margin:0 .4rem;color:#cbd5e1;}
.gl-body{min-height:100vh;display:flex;flex-direction:column;overflow-x:hidden;}
html,body{max-width:100%;}

/* ── Layout shell with sidebar (v0.2) ── */
.gl-shell{display:flex;align-items:stretch;min-height:calc(100vh - 56px - 46px);
  width:100%;max-width:100%;}
.gl-main{flex:1 1 auto;padding:1.5rem 2rem;min-width:0;max-width:100%;overflow-x:hidden;}
/* Inner wrapper keeps content from stretching edge-to-edge on wide screens
   while staying fully fluid on tablets/laptops. */
.gl-main > *{max-width:1400px;}
@media (max-width:992px){
  .gl-main{padding:1rem 1.1rem;}
}
.gl-burger{background:transparent;border:0;color:#fff;font-size:1.25rem;
  line-height:1;cursor:pointer;padding:.25rem .5rem;border-radius:6px;}
.gl-burger:hover{background:rgba(255,255,255,.12);}
/* v0.14: show the burger as "active" while the sidebar is pinned open.
   The burger lives in the navbar (outside the shell), so it carries its
   own state class toggled by JS rather than relying on a shell ancestor. */
.gl-burger.gl-burger-pinned{background:rgba(255,255,255,.18);}

/* Sidebar */
.gl-sidebar{flex:0 0 230px;width:230px;background:#0f172a;border-right:1px solid #1e293b;
  transition:width .18s ease, flex-basis .18s ease;overflow:hidden;}
.gl-nav{display:flex;flex-direction:column;padding:.6rem .5rem;gap:.15rem;}
.gl-nav-item{display:flex;align-items:center;gap:.7rem;padding:.6rem .7rem;border-radius:8px;
  color:#cbd5e1;text-decoration:none;font-size:.92rem;white-space:nowrap;}
.gl-nav-item:hover{background:#1e293b;color:#fff;}
.gl-nav-item.active{background:#2563eb;color:#fff;}
.gl-nav-item.disabled{color:#64748b;cursor:default;}
.gl-nav-item.disabled:hover{background:transparent;color:#64748b;}
.gl-nav-ico{width:1.2rem;text-align:center;font-size:1rem;flex:0 0 auto;}
.gl-nav-txt{flex:1 1 auto;}
.gl-soon{font-size:.62rem;background:#1e293b;color:#94a3b8;border-radius:5px;
  padding:.05rem .35rem;text-transform:uppercase;letter-spacing:.04em;}

/* Collapsed state: hide labels, narrow rail */
.gl-collapsed .gl-sidebar{flex-basis:56px;width:56px;}
.gl-collapsed .gl-nav-txt,.gl-collapsed .gl-soon{display:none;}
.gl-collapsed .gl-nav-item{justify-content:center;gap:0;}

/* ── Auto-minimize sidebar (v0.14) ──────────────────────────────────
   Default behaviour: the shell carries `gl-auto` and starts collapsed to
   the 56px icon rail, giving the user maximum working canvas. On a
   pointer device the rail expands to full width on hover WITHOUT
   reflowing the main content — it overlays instead — so a single glance
   at an icon, then hover, reveals the labels. Clicking the burger PINS
   the sidebar open (adds `gl-pinned`), which overrides the auto-collapse
   until toggled off again. On touch tablets (no hover) the rail stays as
   icons and each icon navigates directly, or the burger pins it open. */

/* When auto mode is on, the rail sits above the main content so expanding
   it does not push the canvas around. */
.gl-auto .gl-sidebar{position:relative;z-index:1040;}

/* Auto + not pinned = collapsed rail by default. */
.gl-auto:not(.gl-pinned) .gl-sidebar{flex-basis:56px;width:56px;}
.gl-auto:not(.gl-pinned) .gl-nav-txt,
.gl-auto:not(.gl-pinned) .gl-soon{display:none;}
.gl-auto:not(.gl-pinned) .gl-nav-item{justify-content:center;gap:0;}

/* Hover-to-peek: on pointer devices, hovering the collapsed rail expands
   it as an overlay (absolute) so the 1400px canvas underneath never
   shifts. Guarded by the hover media feature so touch devices are
   unaffected. */
@media (hover:hover) and (pointer:fine){
  .gl-auto:not(.gl-pinned) .gl-sidebar{
    position:absolute;top:0;bottom:0;left:0;}
  .gl-auto:not(.gl-pinned) .gl-sidebar:hover{
    flex-basis:230px;width:230px;
    box-shadow:4px 0 18px rgba(2,6,23,.35);}
  .gl-auto:not(.gl-pinned) .gl-sidebar:hover .gl-nav-txt,
  .gl-auto:not(.gl-pinned) .gl-sidebar:hover .gl-soon{display:inline;}
  .gl-auto:not(.gl-pinned) .gl-sidebar:hover .gl-nav-item{
    justify-content:flex-start;gap:.7rem;}
  /* Reserve the rail's 56px so the overlay doesn't cover content. */
  .gl-auto:not(.gl-pinned) .gl-main{margin-left:56px;}
}

/* On small screens, sidebar overlays instead of squashing content */
@media (max-width:768px){
  .gl-sidebar{position:fixed;top:56px;bottom:0;left:0;z-index:1030;}
  .gl-collapsed .gl-sidebar{flex-basis:0;width:0;border:0;}
  /* On phones the auto rail also overlays; reset the desktop margin. */
  .gl-auto:not(.gl-pinned) .gl-main{margin-left:0;}
  .gl-auto .gl-sidebar{position:fixed;}
}

/* ── Tablet tuning (v0.19) — Samsung Galaxy Tab A11+ ────────────────
   The A11+ is ~1200px wide in portrait and ~1920px in landscape, and it is a
   TOUCH device (no hover, coarse pointer) — so the desktop hover-to-peek path
   never fires. We keep the icon rail (max working canvas) and let the burger
   pin the labelled sidebar open. On coarse-pointer devices we widen the tap
   targets and, when the rail expands (pinned), overlay it so the canvas never
   reflows. Canvas padding is trimmed so more width is usable for the app. */
@media (pointer:coarse){
  /* Bigger, easier-to-tap nav icons on the rail. */
  .gl-auto:not(.gl-pinned) .gl-nav-item{padding-top:.85rem;padding-bottom:.85rem;}
  /* v0.22: restore the normal collapsible sidebar on tablets. The burger
     pins/unpins it and it sits in-flow (same as desktop) so it reads as a
     proper collapsible sidebar rather than an overlay. */
}

/* Portrait tablets (incl. A11+ portrait ~1200px): trim canvas padding and let
   content use the full usable width. Icon rail stays put for maximum canvas. */
@media (min-width:769px) and (max-width:1280px) and (orientation:portrait){
  .gl-main{padding:1rem 1.1rem;}
  .gl-main > *{max-width:100%;}
}

/* Landscape tablets (A11+ landscape ~1920px): comfortable padding, keep the
   1400px content cap so lines don't get too long on the wide panel. */
@media (min-width:1281px) and (orientation:landscape) and (pointer:coarse){
  .gl-main{padding:1.25rem 1.75rem;}
}

/* ── Tracker ── */
.gl-card{max-width:100%;}
.gl-card .table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.gl-tracker-table{margin-bottom:0;}
.gl-count-badge{font-size:.75rem;font-weight:600;padding:.25rem .7rem;border-radius:20px;
  background:#dbeafe;color:#1e40af;}
.gl-count-badge.all{background:#d1fae5;color:#065f46;}
.gl-tracker-table th{font-size:.72rem;text-transform:uppercase;letter-spacing:.03em;
  color:#64748b;border-bottom:2px solid var(--gl-line);}
.gl-tracker-table td a{text-decoration:none;font-weight:600;}
.gl-row-overdue{background:#fff5f5;}
.gl-prio{font-size:.72rem;font-weight:600;padding:.1rem .5rem;border-radius:6px;}
.gl-prio-routine{background:#e2e8f0;color:#475569;}
.gl-prio-urgent{background:#fef3c7;color:#92400e;}
.gl-prio-critical{background:#fee2e2;color:#991b1b;}
.gl-tag-mother,.gl-tag-aliquot{display:inline-block;font-size:.6rem;font-weight:700;
  border-radius:4px;padding:0 .3rem;margin-left:.3rem;vertical-align:middle;}
.gl-tag-mother{background:#ede9fe;color:#6d28d9;}
.gl-tag-aliquot{background:#cffafe;color:#0e7490;}
/* On narrower screens, drop the least-critical columns so the table fits.
   Columns: 1 AR, 2 Product, 3 Name, 4 Type, 5 Stage, 6 Status, 7 Priority,
            8 Due, 9 Expiry, 10 Registered By. */
@media (max-width:1100px){
  .gl-tracker-table th:nth-child(2),.gl-tracker-table td:nth-child(2),  /* Product */
  .gl-tracker-table th:nth-child(10),.gl-tracker-table td:nth-child(10) /* Registered By */
  {display:none;}
}
@media (max-width:850px){
  .gl-tracker-table th:nth-child(4),.gl-tracker-table td:nth-child(4),  /* Type */
  .gl-tracker-table th:nth-child(9),.gl-tracker-table td:nth-child(9)   /* Expiry */
  {display:none;}
}

/* ── Detail ── */
.gl-detail-head{border-left:5px solid #2563eb;}
.gl-detail-ar{font-size:1.4rem;font-weight:700;color:#1e293b;}
.gl-detail-name{font-size:1rem;color:#334155;margin-top:.15rem;}
.gl-detail-product{font-size:.82rem;color:#2563eb;font-weight:600;margin-top:.1rem;}
.gl-status{font-size:.78rem;font-weight:600;padding:.3rem .8rem;border-radius:20px;
  background:#d1fae5;color:#065f46;}
.gl-status-disposed,.gl-status-to-be-discarded{background:#fee2e2;color:#991b1b;}
.gl-status-archived{background:#e2e8f0;color:#475569;}
.gl-kv td{padding:.35rem 0;font-size:.86rem;border:0;}
.gl-kv td:first-child{color:#64748b;width:45%;}
.gl-tests,.gl-aliquots{font-size:.86rem;padding-left:1.1rem;}
.gl-tests li,.gl-aliquots li{margin:.15rem 0;}
.gl-aliquots a{text-decoration:none;}
.gl-instructions{background:#fef3c7;border-left:4px solid #d97706;padding:.6rem .8rem;
  border-radius:6px;font-size:.85rem;}

/* Timeline */
.gl-timeline{position:relative;padding-left:1rem;}
.gl-tl-item{position:relative;padding:.5rem 0 .5rem 1rem;border-left:2px solid #e2e8f0;}
.gl-tl-item::before{content:"";position:absolute;left:-7px;top:.7rem;width:12px;height:12px;
  border-radius:50%;background:#cbd5e1;border:2px solid #fff;}
.gl-tl-current::before{background:#10b981;}
.gl-tl-stage{font-weight:600;color:#1e293b;font-size:.9rem;}
.gl-tl-current .gl-tl-stage{color:#059669;}
.gl-tl-meta{font-size:.78rem;color:#64748b;margin-top:.15rem;}
.gl-tl-remark{font-size:.78rem;color:#475569;font-style:italic;margin-top:.15rem;}

/* ── Register wizard (v0.3) ── */
.gl-steps{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;}
.gl-step{display:flex;align-items:center;gap:.45rem;}
.gl-step-n{display:inline-flex;align-items:center;justify-content:center;
  width:26px;height:26px;border-radius:50%;background:#e2e8f0;color:#64748b;
  font-size:.8rem;font-weight:700;flex:0 0 auto;}
.gl-step-l{font-size:.82rem;color:#94a3b8;white-space:nowrap;}
.gl-step.active .gl-step-n{background:#2563eb;color:#fff;}
.gl-step.active .gl-step-l{color:#1e293b;font-weight:600;}
.gl-step.past .gl-step-n{background:#10b981;color:#fff;}
.gl-step.past .gl-step-l{color:#475569;}
.gl-step-bar{flex:1 1 18px;min-width:18px;height:2px;background:#e2e8f0;}
.gl-step-bar.past{background:#10b981;}
@media (max-width:680px){.gl-step-l{display:none;}}

.gl-ar-banner{border-left:5px solid #2563eb;}
.gl-ar-big{font-size:1.7rem;font-weight:700;letter-spacing:.02em;color:#1e293b;}

.gl-aliquot-choice{display:flex;gap:.75rem;flex-wrap:wrap;}
.gl-radio-card{flex:1 1 220px;border:1px solid var(--gl-line);border-radius:10px;
  padding:.8rem 1rem;cursor:pointer;display:flex;align-items:center;gap:.6rem;}
.gl-radio-card:hover{border-color:#93c5fd;background:#f8fafc;}
.gl-radio-title{font-size:.92rem;}
.gl-ar-chip{display:inline-block;font-family:monospace;font-size:.8rem;
  background:#eff6ff;color:#1e40af;border:1px solid #bfdbfe;border-radius:6px;
  padding:.15rem .5rem;margin:.15rem .25rem .15rem 0;}
.gl-ar-chip.linkable{text-decoration:none;}
.gl-ar-chip.linkable:hover{background:#dbeafe;}

.gl-summary-banner{background:#f5f3ff;border:1px solid #ddd6fe;font-size:.9rem;}
.gl-badge-purple{background:#ede9fe;color:#6d28d9;border-radius:20px;
  padding:.1rem .6rem;font-size:.75rem;font-weight:600;}
.gl-badge-blue{background:#dbeafe;color:#1e40af;border-radius:20px;
  padding:.1rem .6rem;font-size:.75rem;font-weight:600;}

.gl-detail-tabs .nav-link{font-size:.85rem;padding:.4rem .8rem;}
.gl-tally-ok{color:#065f46;background:#d1fae5;border-radius:8px;padding:.5rem .8rem;
  font-size:.86rem;font-weight:600;}
.gl-tally-bad{color:#991b1b;background:#fee2e2;border-radius:8px;padding:.5rem .8rem;
  font-size:.86rem;font-weight:600;}

.gl-done-card{padding:2.2rem 1.5rem;}
.gl-done-check{width:64px;height:64px;border-radius:50%;background:#d1fae5;color:#059669;
  font-size:2rem;display:flex;align-items:center;justify-content:center;margin:0 auto 1rem;}
.gl-done-list{margin-top:1rem;}

/* ── Stage Movement (v0.4) ── */
.gl-move-tabs .nav-link{background:#e2e8f0;color:#334155;margin-right:.4rem;font-size:.9rem;}
.gl-move-tabs .nav-link.active{background:#2563eb;color:#fff;}
.gl-current-stage{font-size:1.1rem;font-weight:700;color:#2563eb;}

/* ── Discard (v0.5) ── */
.gl-review-badge{font-size:.68rem;background:#fef3c7;color:#92400e;border-radius:12px;
  padding:.1rem .5rem;margin-left:.4rem;font-weight:600;}
.gl-dcr{border:1px solid var(--gl-line);border-radius:10px;padding:.8rem 1rem;margin-bottom:.7rem;}
.gl-dcr:last-child{margin-bottom:0;}
.gl-dcr-status{font-size:.7rem;font-weight:600;border-radius:12px;padding:.1rem .55rem;margin-left:.4rem;}
.gl-dcr-status.pending{background:#fef3c7;color:#92400e;}
.gl-dcr-status.approved{background:#d1fae5;color:#065f46;}
.gl-dcr-status.rejected{background:#e2e8f0;color:#475569;}
.gl-dcr-ars{margin:.5rem 0;}
.gl-dcr-reason{font-size:.85rem;color:#475569;background:#f8fafc;border-radius:6px;
  padding:.4rem .6rem;margin-bottom:.5rem;}
.gl-dcr-actions{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap;}
.gl-dcr-actions .form-control{max-width:260px;}

/* ── Admin (v0.6) ── */
.gl-pill-green{background:#d1fae5;color:#065f46;border-radius:12px;padding:.1rem .55rem;
  font-size:.72rem;font-weight:600;margin-left:.2rem;}
.gl-pill-grey{background:#e2e8f0;color:#475569;border-radius:12px;padding:.1rem .55rem;
  font-size:.72rem;font-weight:600;margin-left:.2rem;}
.gl-role-badge{background:#eff6ff;color:#1e40af;border:1px solid #bfdbfe;border-radius:6px;
  padding:.1rem .5rem;font-size:.76rem;font-weight:600;}
.gl-edit-cell{background:#f8fafc;}
.gl-master-area{font-family:monospace;font-size:.85rem;}
.gl-perm-table th{font-size:.72rem;white-space:nowrap;}
.gl-lvl{font-size:.68rem;font-weight:700;border-radius:5px;padding:.1rem .4rem;text-transform:uppercase;}
.gl-lvl-full{background:#d1fae5;color:#065f46;}
.gl-lvl-view{background:#dbeafe;color:#1e40af;}
.gl-lvl-create{background:#fef3c7;color:#92400e;}
.gl-lvl-none{background:#f1f5f9;color:#cbd5e1;}

/* ── Audit Trail (v0.7) ── */
.gl-interim-note{background:#fffbeb;border-left:4px solid #d97706;border-radius:6px;
  padding:.7rem 1rem;font-size:.85rem;color:#475569;}
.gl-audit-table th{font-size:.72rem;text-transform:uppercase;letter-spacing:.03em;color:#64748b;}
.gl-audit-action{font-size:.7rem;font-weight:600;border-radius:6px;padding:.1rem .5rem;white-space:nowrap;}
.gl-action-stage-move{background:#dbeafe;color:#1e40af;}
.gl-action-sample-receipt{background:#d1fae5;color:#065f46;}
.gl-action-discard-raised{background:#fef3c7;color:#92400e;}
.gl-action-discard-approved{background:#fee2e2;color:#991b1b;}
.gl-action-discard-rejected{background:#e2e8f0;color:#475569;}

/* ── Barcode & Label (v0.8) ── */
.gl-label-preview{width:177px;height:177px;border:1px solid var(--gl-line);
  border-radius:6px;image-rendering:pixelated;background:#fff;}
.gl-stage-preview{max-width:340px;width:100%;border:1px solid var(--gl-line);
  border-radius:8px;background:#fff;}
.gl-label-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:1rem;}
.gl-label-tile{text-align:center;border:1px solid var(--gl-line);border-radius:10px;
  padding:.6rem;background:#fff;}

/* ── Stage Movement v0.9 ── */
.gl-pill-amber{background:#fef3c7;color:#92400e;border-radius:12px;padding:.1rem .55rem;
  font-size:.72rem;font-weight:600;margin-left:.2rem;}

/* ── Editable role-permission grid (v0.10) ───────────────────────── */
.gl-perm-select{font-size:.72rem;font-weight:600;width:auto;min-width:78px;display:inline-block;text-transform:uppercase;}
.gl-perm-select.gl-lvl-full{background:#d1fae5;color:#065f46;}
.gl-perm-select.gl-lvl-view{background:#dbeafe;color:#1e40af;}
.gl-perm-select.gl-lvl-create{background:#fef3c7;color:#92400e;}
.gl-perm-select.gl-lvl-none{background:#f1f5f9;color:#64748b;}

/* ── Idle auto-logout warning modal (v0.15) ── */
.gl-idle-overlay{position:fixed;inset:0;z-index:2000;display:flex;
  align-items:center;justify-content:center;background:rgba(2,6,23,.55);
  padding:1rem;}
.gl-idle-modal{background:#fff;border-radius:14px;max-width:380px;width:100%;
  padding:1.5rem 1.5rem 1.35rem;box-shadow:0 18px 50px rgba(2,6,23,.4);
  text-align:center;}
.gl-idle-title{font-size:1.15rem;font-weight:700;margin:0 0 .4rem;color:#0f172a;}
.gl-idle-desc{font-size:.95rem;color:#475569;margin:0 0 1.1rem;}
.gl-idle-desc #glIdleCount{font-weight:700;color:#b91c1c;}

/* ── In-app camera scanner (v0.16) ── */
.gl-scan-btn{white-space:nowrap;}
.gl-scan-overlay{position:fixed;inset:0;z-index:2100;display:flex;
  align-items:center;justify-content:center;background:rgba(2,6,23,.7);padding:1rem;}
.gl-scan-modal{background:#fff;border-radius:14px;max-width:460px;width:100%;
  overflow:hidden;box-shadow:0 18px 50px rgba(2,6,23,.5);display:flex;flex-direction:column;
  max-height:92vh;}
.gl-scan-head{display:flex;align-items:center;justify-content:space-between;
  padding:.8rem 1rem;border-bottom:1px solid #e2e8f0;}
.gl-scan-title{font-weight:700;color:#0f172a;}
.gl-scan-x{background:transparent;border:0;font-size:1.5rem;line-height:1;
  color:#64748b;cursor:pointer;padding:0 .3rem;}
/* v0.19 portrait fix: the video box is capped in height so a portrait camera
   stream never balloons to fill the whole screen (which previously blocked the
   background and made aiming hard). object-fit:cover keeps it filled; the
   height cap uses a fraction of the viewport so the modal, message, reticle and
   controls stay visible in BOTH portrait and landscape. */
.gl-scan-videowrap{position:relative;background:#000;width:100%;
  height:46vh;max-height:360px;min-height:200px;overflow:hidden;}
.gl-scan-video{width:100%;height:100%;object-fit:cover;display:block;}
.gl-scan-reticle{position:absolute;inset:16% 12%;border:3px solid rgba(37,99,235,.9);
  border-radius:12px;box-shadow:0 0 0 100vmax rgba(0,0,0,.15);pointer-events:none;}
/* On short landscape (e.g. tablet landscape), shrink the video box further so
   the whole modal fits without scrolling. */
@media (orientation:landscape) and (max-height:600px){
  .gl-scan-videowrap{height:52vh;max-height:300px;}
  .gl-scan-modal{max-width:520px;}
}
.gl-scan-flash .gl-scan-videowrap::after{content:"";position:absolute;inset:0;
  background:rgba(255,255,255,.7);animation:glscanflash .16s ease-out;}
@keyframes glscanflash{from{opacity:1;}to{opacity:0;}}
.gl-scan-msg{padding:.6rem 1rem;font-size:.9rem;color:#475569;min-height:1.2rem;}
.gl-scan-msg.gl-scan-ok{color:#047857;}
.gl-scan-msg.gl-scan-warn{color:#b45309;}
.gl-scan-msg.gl-scan-err{color:#b91c1c;}
.gl-scan-list{padding:0 1rem;overflow-y:auto;max-height:26vh;}
.gl-scan-count{font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;
  color:#64748b;margin:.2rem 0 .4rem;}
.gl-scan-empty{font-size:.85rem;color:#94a3b8;padding:.3rem 0;}
.gl-scan-row{display:flex;align-items:center;justify-content:space-between;
  padding:.3rem .5rem;border:1px solid #e2e8f0;border-radius:8px;margin-bottom:.3rem;}
.gl-scan-code{font-family:monospace;font-size:.85rem;color:#0f172a;}
.gl-scan-del{background:transparent;border:0;color:#b91c1c;font-size:1.1rem;
  line-height:1;cursor:pointer;padding:0 .3rem;}
.gl-scan-actions{display:flex;gap:.5rem;padding:.8rem 1rem;border-top:1px solid #e2e8f0;}

/* ── Register mode landing (v0.17) ── */
.gl-mode-card{display:flex;flex-direction:column;text-align:left;min-height:210px;}
.gl-mode-ico{font-size:1.8rem;line-height:1;margin-bottom:.5rem;}
.gl-mode-disabled{opacity:.72;background:#f8fafc;}

/* ── Thumb-reachable floating scan button (v0.20) ──────────────────
   A fixed bottom-right FAB so the scan action is always under the right
   thumb while the tablet is held right-handed (sidebar is on the left, so
   the right edge is free). Used on scan-capable pages. It reuses the normal
   [data-gl-scan] wiring — it's just positioned for reach. */
/* v0.24: the scan FAB defaults to the RIGHT edge, vertically centered (best
   thumb reach when the tablet is held right-handed in landscape). It is
   DRAGGABLE — the user can drop it anywhere and the position is remembered
   (per-device, via localStorage). JS sets inline left/top when moved; until
   then these defaults apply. */
.gl-scan-fab{position:fixed;right:1rem;top:50%;transform:translateY(-50%);z-index:1200;
  display:inline-flex;align-items:center;gap:.6rem;
  padding:1rem 1.8rem;border:0;border-radius:999px;
  background:#0f766e;color:#fff;font-weight:700;font-size:1.15rem;
  box-shadow:0 8px 22px rgba(2,6,23,.35);cursor:grab;
  touch-action:none;user-select:none;-webkit-user-select:none;}
.gl-scan-fab:hover{background:#0e6b63;}
.gl-scan-fab.gl-dragging{cursor:grabbing;opacity:.9;box-shadow:0 12px 30px rgba(2,6,23,.5);}
/* When JS has positioned it (inline left/top set), neutralise the default
   right/top/transform so inline coordinates take full effect. */
.gl-scan-fab.gl-positioned{right:auto;transform:none;}
.gl-scan-fab .gl-fab-ico{font-size:1.7rem;line-height:1;}
/* Content no longer needs bottom clearance (FAB is on the right edge), but keep
   a little so a bottom-dropped FAB doesn't sit on the footer. */
@media (pointer:coarse){ .gl-main{padding-bottom:2rem;} }

/* ── Fit-on-one-page tuning for tablet landscape (v0.20) ───────────
   Trim vertical rhythm on the key operational pages so they fit an A11+
   landscape screen without scrolling where the content reasonably allows.
   Long lists / big forms will still scroll — that's expected. */
@media (orientation:landscape) and (pointer:coarse){
  .gl-main{padding-top:1rem;padding-bottom:1rem;}
  .gl-card{margin-bottom:.85rem;}
  .gl-instructions{margin-bottom:.85rem;padding:.6rem .8rem;font-size:.9rem;}
  h1.h4{margin-bottom:.6rem !important;}
}

/* ── Slow-connection resilience UI (v0.20) ─────────────────────────── */
.gl-netbar{position:fixed;top:0;left:0;height:3px;width:100%;
  background:#14b8a6;transform-origin:left;transform:scaleX(0);
  transition:transform .3s ease;z-index:3000;opacity:0;}
.gl-netbar.gl-netbar-active{opacity:1;}
.gl-spin{display:inline-block;width:.8em;height:.8em;vertical-align:-.05em;
  border:2px solid rgba(255,255,255,.5);border-top-color:#fff;border-radius:50%;
  animation:glspin .6s linear infinite;}
@keyframes glspin{to{transform:rotate(360deg);}}
.gl-slow-toast{position:fixed;left:50%;bottom:1.25rem;transform:translateX(-50%) translateY(20px);
  background:#0f172a;color:#fff;padding:.6rem 1rem;border-radius:999px;
  font-size:.9rem;box-shadow:0 8px 22px rgba(2,6,23,.4);z-index:3000;
  opacity:0;transition:opacity .2s ease,transform .2s ease;pointer-events:none;}
.gl-slow-toast.gl-slow-show{opacity:1;transform:translateX(-50%) translateY(0);}

/* ══════════════════════════════════════════════════════════════════
   eSign (v1.1) — electronic signature module
   Reuses the existing token palette (--gl-accent, --gl-line, slate
   greys) so the module reads as part of the same product rather than
   a bolt-on. New classes are namespaced .gl-es-* to avoid any chance
   of colliding with the SMM styles above.
   ══════════════════════════════════════════════════════════════════ */

/* ── Status pills ──────────────────────────────────────────────────
   One class per Envelope/Slot status value, so templates can emit
   `class="gl-es-status {{ obj.status }}"` and the right colour lands
   without a conditional in the template. */
.gl-es-status{display:inline-block;font-size:.7rem;font-weight:600;
  border-radius:12px;padding:.15rem .6rem;white-space:nowrap;
  text-transform:capitalize;}
.gl-es-status.draft{background:#e2e8f0;color:#475569;}
.gl-es-status.sent{background:#dbeafe;color:#1e40af;}
.gl-es-status.completed{background:#d1fae5;color:#065f46;}
.gl-es-status.voided{background:#e2e8f0;color:#64748b;}
.gl-es-status.declined{background:#fee2e2;color:#991b1b;}
.gl-es-status.pending{background:#f1f5f9;color:#64748b;}
.gl-es-status.active{background:#fef3c7;color:#92400e;}
.gl-es-status.signed{background:#d1fae5;color:#065f46;}

/* ── Progress bar ── */
.gl-es-bar{height:6px;border-radius:4px;background:#e2e8f0;overflow:hidden;}
.gl-es-bar > span{display:block;height:100%;background:#10b981;
  transition:width .25s ease;}
.gl-es-count{font-size:.7rem;color:#64748b;}

/* ── "Waiting for you" rows ── */
.gl-es-pending{display:flex;align-items:center;gap:.9rem;
  padding:.7rem .85rem;border:1px solid var(--gl-line);border-radius:10px;
  margin-bottom:.5rem;background:#fff;}
.gl-es-pending:last-child{margin-bottom:0;}
.gl-es-title{font-weight:600;text-decoration:none;color:#1e293b;
  display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.gl-es-title:hover{color:var(--gl-accent);}
.gl-es-sub{margin-top:.2rem;display:flex;align-items:center;gap:.4rem;
  flex-wrap:wrap;}
.gl-es-meaning{font-size:.72rem;font-weight:600;border-radius:6px;
  padding:.1rem .5rem;background:#eff6ff;color:#1e40af;
  border:1px solid #bfdbfe;}
.gl-es-callout{border-left:5px solid #d97706;background:#fffbeb;}

/* ── Sequence chip ── */
.gl-es-chip{display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border-radius:50%;background:var(--gl-accent);
  color:#fff;font-size:.75rem;font-weight:700;flex:0 0 auto;}

/* ── Document canvas (prepare + sign) ──────────────────────────────
   The stage scrolls; the page wrapper is sized in JS to match the
   rendered canvas exactly so the absolutely-positioned overlay shares
   its coordinate space. */
.gl-es-stage{background:#f1f5f9;padding:12px;overflow:auto;
  max-height:78vh;display:flex;justify-content:center;
  border-radius:0 0 14px 14px;}
.gl-es-page{position:relative;background:#fff;flex:0 0 auto;
  box-shadow:0 2px 12px rgba(15,23,42,.16);}
.gl-es-page canvas{display:block;}
.gl-es-overlay{position:absolute;inset:0;}

/* ── Placement boxes ──────────────────────────────────────────────
   pointer-events must stay on the box itself (it is draggable) while
   the overlay behind it is inert, so clicks that miss a box fall
   through to the page rather than being swallowed. */
.gl-es-box{position:absolute;box-sizing:border-box;
  border:2px solid var(--gl-accent);border-radius:5px;
  background:rgba(37,99,235,.10);cursor:move;overflow:hidden;
  display:flex;align-items:stretch;user-select:none;
  -webkit-user-select:none;touch-action:none;}
.gl-es-box.dragging{opacity:.85;box-shadow:0 6px 18px rgba(2,6,23,.3);
  border-style:dashed;}
.gl-es-box-seq{flex:0 0 auto;width:18px;background:var(--gl-accent);
  color:#fff;font-size:.62rem;font-weight:700;display:flex;
  align-items:center;justify-content:center;}
.gl-es-box-body{flex:1 1 auto;min-width:0;padding:3px 5px;
  display:flex;flex-direction:column;justify-content:center;}
.gl-es-box-name{font-size:.72rem;font-weight:700;color:#1e293b;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.gl-es-box-meaning{font-size:.62rem;color:#1e40af;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* Resize grip — sits in the corner, styled as a visible affordance
   because a hidden resize target on a touch tablet is unfindable. */
.gl-es-box-grip{position:absolute;right:0;bottom:0;width:14px;height:14px;
  background:var(--gl-accent);cursor:nwse-resize;
  clip-path:polygon(100% 0,100% 100%,0 100%);}
/* The signer's own block on the signing page: green, not draggable. */
.gl-es-box-mine{border-color:#059669;background:rgba(16,185,129,.12);
  cursor:default;animation:glesPulse 2.2s ease-in-out infinite;}
.gl-es-box-mine .gl-es-box-name{color:#065f46;}
.gl-es-box-mine .gl-es-box-meaning{color:#047857;}
@keyframes glesPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(16,185,129,.45);}
  50%    {box-shadow:0 0 0 7px rgba(16,185,129,0);}
}

/* ── Slot editor rows (left panel of the prepare screen) ── */
.gl-es-slotrow{border:1px solid var(--gl-line);border-radius:10px;
  padding:.6rem .7rem;margin-bottom:.55rem;background:#f8fafc;}
.gl-es-slotrow:last-child{margin-bottom:0;}
.gl-es-slotrow [data-pageinfo]{cursor:pointer;text-decoration:underline;
  text-decoration-style:dotted;}

/* ── Event feed ── */
.gl-es-events{max-height:520px;overflow-y:auto;}
.gl-es-event{padding:.6rem .9rem;border-bottom:1px solid #f1f5f9;}
.gl-es-event:last-child{border-bottom:0;}
.gl-es-evt{font-size:.66rem;font-weight:600;border-radius:6px;
  padding:.1rem .45rem;white-space:nowrap;background:#e2e8f0;color:#475569;}
.gl-es-evt.created{background:#e2e8f0;color:#475569;}
.gl-es-evt.sent,.gl-es-evt.invite_sent,.gl-es-evt.reminded{background:#dbeafe;color:#1e40af;}
.gl-es-evt.viewed{background:#f1f5f9;color:#64748b;}
.gl-es-evt.signed{background:#d1fae5;color:#065f46;}
.gl-es-evt.completed{background:#a7f3d0;color:#065f46;}
.gl-es-evt.declined,.gl-es-evt.auth_failed{background:#fee2e2;color:#991b1b;}
.gl-es-evt.voided{background:#e2e8f0;color:#64748b;}
.gl-es-evt.guest_created{background:#ede9fe;color:#6d28d9;}

/* ── Hashes ── */
.gl-es-hash{font-family:monospace;font-size:.66rem;color:#94a3b8;
  margin-top:.25rem;}
.gl-es-hash-full{font-family:monospace;font-size:.72rem;color:#475569;
  background:#f1f5f9;border:1px solid var(--gl-line);border-radius:6px;
  padding:.45rem .6rem;word-break:break-all;line-height:1.5;}

/* ── Typed-signature input ──────────────────────────────────────────
   Italic serif so the field reads as a signature while being typed.
   Cursive webfonts were rejected deliberately: they add a network
   dependency to the most critical screen in the product, and if the
   font fails to load the signer sees something different from what
   gets stamped. The stamp uses Helvetica-BoldOblique, which this
   approximates closely enough that there is no surprise. */
.gl-es-sigfont{font-family:Georgia,"Times New Roman",serif;
  font-style:italic;font-size:1.15rem;color:#0f4c81;
  letter-spacing:.01em;}

/* ── Guest portal shell ── */
.gl-guest-main{flex:1 1 auto;width:100%;max-width:1180px;
  margin:0 auto;padding:1.5rem 1.25rem;}
@media (max-width:992px){.gl-guest-main{padding:1rem 1rem;}}

/* ── Small-screen tuning ── */
@media (max-width:992px){
  .gl-es-stage{max-height:60vh;}
}
@media (max-width:576px){
  .gl-es-pending{flex-direction:column;align-items:stretch;gap:.6rem;}
  .gl-es-pending .btn{width:100%;}
}
