/* RevRaptor -- brand foundation and app UI.
   Colours are the approved brand constants; nothing else hardcodes a hex. */

:root {
    --volt:        #C8F135;   /* primary / CTA */
    --redline:     #FF6B2C;   /* alerts, urgency */
    --jungle:      #0D1512;   /* backgrounds */
    --offwhite:    #F4F6F0;   /* text on dark */

    --surface:     #131E1A;   /* raised panels against --jungle */
    --surface-2:   #1A2823;   /* hover / nested panels */
    --line:        #24332D;   /* hairlines */
    --muted:       #8FA098;   /* secondary text */

    --radius:      10px;
    --radius-lg:   16px;
    --font:        "Space Grotesk", "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--jungle);
    color: var(--offwhite);
    font-family: var(--font);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--volt); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { font-weight: 700; letter-spacing: -0.015em; line-height: 1.15; margin: 0 0 0.5em; }
h1 { font-size: clamp(1.6rem, 4vw, 2.2rem); }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.05rem; }

.muted   { color: var(--muted); }
.redline { color: var(--redline); }
.small   { font-size: 0.875rem; }

/* ------------------------------------------------------------------ layout */

/* width:100% is load-bearing, and not obviously so.
   .shell is a column flex container, so .main is a flex item and its width is
   the cross axis. A cross-axis auto margin -- the "margin: 0 auto" that
   centres the column -- switches the item out of stretch and into
   shrink-to-fit, and shrink-to-fit on a flex item resolves to max-content.
   So .main sized itself to its widest descendant and dragged the whole page
   sideways with it: at 375px the admin pages laid out 795px wide, and every
   overflow-x:auto wrapper inside (the admin tables, the copy blocks) was
   pointless because its parent had already grown rather than let it scroll.
   An explicit width puts it back to filling .shell; max-width still caps it
   on a desktop and the auto margins still centre it there. */
.main { width: 100%; max-width: 940px; min-width: 0; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

.main--bare { max-width: 420px; padding-top: 3.5rem; }


/* --------------------------------------------------------------------- nav */


.pill {
    display: inline-block; min-width: 1.35em; margin-left: 0.4em; padding: 0 0.4em;
    border-radius: 999px; background: var(--volt); color: var(--jungle);
    font-size: 0.72rem; font-weight: 700; text-align: center; line-height: 1.5em;
}

/* ------------------------------------------------------------- state cards */

.statecard {
    display: flex; align-items: center; gap: 1.75rem; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius-lg); padding: 1.75rem; margin-bottom: 2rem;
}
.statecard__art { width: 150px; height: 150px; flex-shrink: 0; }
.statecard__text { flex: 1; min-width: 220px; }
.statecard__text h2 { margin-bottom: 0.35em; }
.statecard__text p { margin: 0; }

/* ------------------------------------------------------------------- cards */

.card {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius-lg); padding: 1.25rem 1.5rem; margin-bottom: 1rem;
}
.card--link { display: block; color: inherit; transition: border-color .12s, background .12s; }
.card--link:hover { border-color: var(--volt); background: var(--surface-2); text-decoration: none; }

.hunt__meta {
    display: flex; gap: 1rem; flex-wrap: wrap;
    font-size: 0.8rem; color: var(--muted); margin-bottom: 0.5rem;
}
.hunt__title { margin: 0 0 0.4em; font-size: 1.15rem; }
.card--link:hover .hunt__title { color: var(--volt); }
.hunt__why { margin: 0.6em 0 0; font-size: 0.92rem; color: var(--muted); }
.hunt__why strong { color: var(--redline); }

.tag {
    display: inline-block; padding: 0.15em 0.6em; border-radius: 999px;
    border: 1px solid var(--line); font-size: 0.72rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
}
.tag--new     { border-color: var(--volt);    color: var(--volt); }
.tag--ran     { border-color: var(--volt);    color: var(--volt); }
.tag--skipped { color: var(--muted); }
.tag--urgent  { border-color: var(--redline); color: var(--redline); }

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

.btn {
    display: inline-block; padding: 0.7em 1.4em; border: 0;
    border-radius: var(--radius); background: var(--volt); color: var(--jungle);
    font: inherit; font-weight: 700; cursor: pointer; text-align: center;
}
.btn:hover { filter: brightness(1.08); text-decoration: none; }
.btn--urgent { background: var(--redline); color: var(--offwhite); }
.btn--ghost  { background: transparent; color: var(--offwhite); border: 1px solid var(--line); }
.btn--ghost:hover { border-color: var(--muted); filter: none; }
.btn--full   { display: block; width: 100%; }
.btn--sm     { padding: 0.45em 0.9em; font-size: 0.85rem; }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; }

.btnrow { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-top: 1.5rem; }

/* ------------------------------------------------------------------- forms */

label { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 0.4em; }
.hint { font-weight: 400; color: var(--muted); font-size: 0.84rem; }

input[type=text], input[type=email], input[type=password], input[type=url],
input[type=number], select, textarea {
    width: 100%; padding: 0.7em 0.85em; margin-bottom: 1.1rem;
    background: var(--jungle); color: var(--offwhite);
    border: 1px solid var(--line); border-radius: var(--radius);
    font: inherit;
}
input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--volt); outline-offset: 1px; border-color: var(--volt);
}
textarea { min-height: 90px; resize: vertical; }

.checks { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.1rem; }
.checks label {
    display: inline-flex; align-items: center; gap: 0.45em; margin: 0;
    padding: 0.45em 0.85em; border: 1px solid var(--line);
    border-radius: 999px; cursor: pointer; font-weight: 500; font-size: 0.9rem;
}
.checks label:has(input:checked) { border-color: var(--volt); color: var(--volt); }
.checks input { margin: 0; accent-color: var(--volt); }

input[type=range] { width: 100%; accent-color: var(--volt); margin-bottom: 0.5rem; }
.rangeends { display: flex; justify-content: space-between; font-size: 0.82rem; color: var(--muted); }

.flash {
    padding: 0.85em 1.1em; border-radius: var(--radius); margin-bottom: 1.5rem;
    border: 1px solid var(--line); background: var(--surface); font-size: 0.94rem;
}
.flash--ok    { border-color: var(--volt); }
.flash--error { border-color: var(--redline); }

.error {
    padding: 0.85em 1.1em; border-radius: var(--radius); margin-bottom: 1.25rem;
    border: 1px solid var(--redline); color: var(--offwhite);
    background: rgba(255, 107, 44, 0.08); font-size: 0.94rem;
}

/* -------------------------------------------------------------- hunt detail */

.channel { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 1rem; overflow: hidden; }
.channel__head {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: 0.7em 1em; background: var(--surface-2); font-weight: 600; font-size: 0.9rem;
}
.channel__body {
    padding: 1em; margin: 0; white-space: pre-wrap; word-wrap: break-word;
    font-family: inherit; font-size: 0.94rem; line-height: 1.6; background: var(--jungle);
}
.channel__subject {
    padding: 0.7em 1em; border-bottom: 1px solid var(--line);
    font-size: 0.9rem; color: var(--muted); background: var(--jungle);
}
.channel__subject strong { color: var(--offwhite); }
.is-copied { background: var(--volt) !important; color: var(--jungle) !important; }

.checklist { list-style: none; padding: 0; margin: 0; counter-reset: step; }
.checklist li {
    display: flex; align-items: flex-start; gap: 0.75rem;
    padding: 0.75em 0; border-bottom: 1px solid var(--line);
}
.checklist li:last-child { border-bottom: 0; }
.checklist input { margin-top: 0.35em; accent-color: var(--volt); flex-shrink: 0; }
.checklist li.is-done { color: var(--muted); text-decoration: line-through; }

.factgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; }
.fact__label {
    font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted); margin-bottom: 0.3em;
}

.stat { display: flex; gap: 2.5rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.stat__n { font-size: 1.9rem; font-weight: 700; color: var(--volt); line-height: 1; }
.stat__l { font-size: 0.82rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }

/* Rev's art */
.rev { display: block; }
.rev--head { width: 128px; height: 128px; }
.rev--pose { width: 256px; height: 256px; }
.rev--hero { width: 512px; height: 512px; max-width: 100%; }

@media (max-width: 620px) {
    .nav { gap: 0.85rem; }
    .nav__links { order: 3; width: 100%; }
    .statecard { gap: 1.25rem; padding: 1.25rem; }
    .statecard__art { width: 96px; height: 96px; }
}

/* =========================================================================
   Sidebar shell
   The sidebar is fixed and always present on desktop; collapsing narrows it to
   an icon rail rather than hiding it, so navigation never disappears. Below
   900px it becomes an off-canvas drawer behind a hamburger.
   ========================================================================= */

:root { --side-w: 248px; --side-w-collapsed: 68px; }

body.has-sidebar { padding-left: var(--side-w); transition: padding-left .18s ease; }
html.sidebar-collapsed body.has-sidebar { padding-left: var(--side-w-collapsed); }

.side {
    position: fixed; inset: 0 auto 0 0; z-index: 40;
    width: var(--side-w);
    display: flex; flex-direction: column;
    background-color: var(--surface);
    border-right: 1px solid var(--line);
    transition: width .18s ease, transform .2s ease;
    overflow: hidden;
}
html.sidebar-collapsed .side { width: var(--side-w-collapsed); }

.side__top {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.5rem; padding: 1.15rem 1rem 0.9rem;
}
.side__brand { display: block; line-height: 0; flex: 1; min-width: 0; }
.side__lockup { width: 150px; max-width: 100%; height: auto; display: block; }
.side__icon   { width: 36px; height: 36px; display: none; }
html.sidebar-collapsed .side__lockup { display: none; }
html.sidebar-collapsed .side__icon   { display: block; }

.side__collapse {
    flex-shrink: 0; width: 26px; height: 26px; padding: 0;
    background: transparent; border: 1px solid var(--line); border-radius: 7px;
    color: var(--muted); font-size: 15px; line-height: 1; cursor: pointer;
}
.side__collapse:hover { color: var(--offwhite); border-color: var(--muted); }
html.sidebar-collapsed .side__collapse { transform: rotate(180deg); }

.side__shop {
    display: flex; align-items: center; gap: 0.7rem;
    padding: 0.6rem 1rem 1rem; margin-bottom: 0.35rem;
    border-bottom: 1px solid var(--line);
}
.side__avatar {
    width: 40px; height: 40px; flex-shrink: 0;
    border-radius: 50%; background: var(--surface-2); padding: 2px;
}
.side__shopmeta { min-width: 0; }
.side__shopname {
    font-weight: 700; font-size: 0.92rem; line-height: 1.25;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.side__shopcity { font-size: 0.78rem; color: var(--muted); }
html.sidebar-collapsed .side__shopmeta { display: none; }
html.sidebar-collapsed .side__shop { justify-content: center; padding-left: 0; padding-right: 0; }

.side__nav { flex: 1; padding: 0.5rem 0.6rem; overflow-y: auto; }
.side__link {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.62em 0.75em; margin-bottom: 2px; border-radius: 9px;
    color: var(--muted); font-weight: 600; font-size: 0.93rem;
    white-space: nowrap;
}
.side__link:hover { background: var(--surface-2); color: var(--offwhite); text-decoration: none; }
.side__link.is-active { background: var(--surface-2); color: var(--volt); }
.side__link--quiet { font-weight: 500; font-size: 0.87rem; }
.side__divider { height: 1px; background: var(--line); margin: 0.6rem 0.75em; }

.side__bottom { padding: 0.5rem 0.6rem 1rem; border-top: 1px solid var(--line); }
.side__credits {
    display: flex; align-items: baseline; gap: 0.4rem;
    padding: 0.55em 0.75em; margin-bottom: 0.25rem; border-radius: 9px;
    color: var(--muted); font-size: 0.87rem;
}
.side__credits:hover { background: var(--surface-2); text-decoration: none; }
.side__creditsn { font-size: 1.15rem; font-weight: 700; color: var(--volt); }

.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--redline); flex-shrink: 0; }

/* Collapsed: icons only. Labels leave the layout but stay in the DOM for
   screen readers. */
html.sidebar-collapsed .side__label { display: none; }
html.sidebar-collapsed .side__link,
html.sidebar-collapsed .side__credits { justify-content: center; padding-left: 0; padding-right: 0; }

.shell { min-height: 100vh; display: flex; flex-direction: column; }
.shell .main { flex: 1; }

.drawer-toggle { display: none; }
.scrim { position: fixed; inset: 0; z-index: 39; background: rgba(0, 0, 0, 0.55); }

@media (max-width: 900px) {
    body.has-sidebar,
    html.sidebar-collapsed body.has-sidebar { padding-left: 0; }

    .side { transform: translateX(-100%); width: var(--side-w); box-shadow: 0 0 40px rgba(0,0,0,.5); }
    html.sidebar-collapsed .side { width: var(--side-w); }
    body.drawer-open .side { transform: translateX(0); }

    /* On mobile the drawer is open or closed -- never the icon rail. */
    html.sidebar-collapsed .side__lockup { display: block; }
    html.sidebar-collapsed .side__icon { display: none; }
    html.sidebar-collapsed .side__label { display: inline; }
    html.sidebar-collapsed .side__shopmeta { display: block; }
    html.sidebar-collapsed .side__shop { justify-content: flex-start; padding: 0.6rem 1rem 1rem; }
    html.sidebar-collapsed .side__link,
    html.sidebar-collapsed .side__credits { justify-content: flex-start; padding-left: 0.75em; padding-right: 0.75em; }
    .side__collapse { display: none; }

    .drawer-toggle {
        display: flex; flex-direction: column; justify-content: center; gap: 4px;
        position: fixed; top: 12px; left: 12px; z-index: 41;
        width: 44px; height: 44px; padding: 0 10px;   /* 44 is the touch-target floor */
        background: var(--surface); border: 1px solid var(--line);
        border-radius: 10px; cursor: pointer;
    }
    .drawer-toggle span {
        display: block; height: 2px; background: var(--offwhite); border-radius: 2px;
        transition: transform .18s ease, opacity .12s ease;
    }
    body.drawer-open .drawer-toggle span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
    body.drawer-open .drawer-toggle span:nth-child(2) { opacity: 0; }
    body.drawer-open .drawer-toggle span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

    .main { padding-top: 4.25rem; }
}

.foot {
    display: flex; gap: 1rem; align-items: center;
    max-width: 940px; margin: 0 auto; padding: 2rem 1.25rem 3rem;
    color: var(--muted); font-size: 0.8rem;
}

/* ------------------------------------------------------- toggles & pills */

.toggle-row {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 1.5rem; padding: 0.9rem 0; border-bottom: 1px solid var(--line);
}
.toggle-row:last-child { border-bottom: 0; }
.toggle-row__text { min-width: 0; }
.toggle-row__text strong { display: block; font-size: 0.95rem; }
.toggle-row__text span { font-size: 0.85rem; color: var(--muted); }
.toggle-row__controls { display: flex; gap: 1rem; flex-shrink: 0; }
.toggle-row__controls label {
    display: flex; align-items: center; gap: 0.35em; margin: 0;
    font-size: 0.85rem; font-weight: 500; cursor: pointer;
}
.toggle-row__controls input { accent-color: var(--volt); margin: 0; }
.toggle-row__controls input:disabled + span { color: var(--muted); }

.segment { display: inline-flex; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; }
.segment label {
    position: relative; margin: 0; padding: 0.55em 1.1em; cursor: pointer;
    font-size: 0.9rem; font-weight: 600; color: var(--muted);
}
.segment input { position: absolute; opacity: 0; pointer-events: none; }
.segment label:has(input:checked) { background: var(--volt); color: var(--jungle); }

/* --------------------------------------------------------- what's new */

.entry { padding: 1.5rem 0; border-bottom: 1px solid var(--line); }
.entry:last-child { border-bottom: 0; }
.entry__date {
    font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--muted); margin-bottom: 0.4em;
}
.entry ul { margin: 0.6em 0 0; padding-left: 1.15em; }
.entry li { margin-bottom: 0.4em; }

/* Shown only once the browser offers an install prompt. */
.install { display: none; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.install.is-ready { display: flex; }

/* =========================================================================
   Toggle switches
   Real switches, not checkboxes. The native input stays in the DOM and keeps
   focus and keyboard behaviour; the track and thumb are painted over it.
   ========================================================================= */

.switch {
    display: inline-flex; align-items: center; gap: 0.5em;
    margin: 0; cursor: pointer; font-size: 0.85rem; font-weight: 500;
    color: var(--muted); user-select: none;
}
.switch__label { min-width: 3.1em; }
.switch input {
    position: absolute; opacity: 0; width: 0; height: 0; margin: 0;
}
.switch__track {
    position: relative; display: block; flex-shrink: 0;
    width: 42px; height: 24px; border-radius: 999px;
    background: var(--surface-2); border: 1px solid var(--line);
    transition: background .16s ease, border-color .16s ease;
}
.switch__thumb {
    position: absolute; top: 2px; left: 2px;
    width: 18px; height: 18px; border-radius: 50%;
    background: var(--muted);
    transition: transform .16s ease, background .16s ease;
}
.switch input:checked ~ .switch__track {
    background: var(--volt); border-color: var(--volt);
}
.switch input:checked ~ .switch__track .switch__thumb {
    transform: translateX(18px); background: var(--jungle);
}
.switch input:checked ~ .switch__label,
.switch:has(input:checked) .switch__label { color: var(--offwhite); }
.switch input:focus-visible ~ .switch__track {
    outline: 2px solid var(--volt); outline-offset: 2px;
}
/* Locked rows (transactional notifications) read as fixed, not broken. */
.switch.is-locked { cursor: not-allowed; opacity: 0.5; }

/* Brief confirmation that an auto-saved row landed. */
.toggle-row.is-saved { animation: rowsaved 1.1s ease; }
@keyframes rowsaved {
    0%   { background: rgba(200, 241, 53, 0.10); }
    100% { background: transparent; }
}
.toggle-row.is-failed { animation: none; background: rgba(255, 107, 44, 0.10); }

@media (prefers-reduced-motion: reduce) {
    .switch__track, .switch__thumb { transition: none; }
    .toggle-row.is-saved { animation: none; }
}

/* ------------------------------------------------------------ install ---- */

.install-card {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1.5rem; flex-wrap: wrap;
}
.install-card__text { display: flex; flex-direction: column; gap: 0.2rem; min-width: 220px; flex: 1; }

.side__install {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    width: 100%; margin-bottom: 0.5rem; padding: 0.6em 0.75em;
    background: transparent; border: 1px dashed var(--line); border-radius: 9px;
    color: var(--volt); font: inherit; font-size: 0.87rem; font-weight: 600;
    cursor: pointer; text-align: left; white-space: nowrap;
}
.side__install:hover { background: var(--surface-2); border-color: var(--volt); }
.side__installicon { font-size: 1rem; line-height: 1; }
html.sidebar-collapsed .side__install { justify-content: center; padding-left: 0; padding-right: 0; }

/* ----------------------------------------------------------- timeline ---- */

.timeline__month { margin-bottom: 2.5rem; }
.timeline__label {
    position: sticky; top: 0; z-index: 2;
    margin: 0 0 0.25rem; padding: 0.6rem 0;
    background: var(--jungle);
    font-size: 0.8rem; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--muted);
    border-bottom: 1px solid var(--line);
}
.timeline .entry {
    position: relative;
    padding: 1.4rem 0 1.4rem 1.5rem;
    border-bottom: 1px solid var(--line);
}
.timeline .entry:last-child { border-bottom: 0; }
/* The timeline rail and its node. */
.timeline .entry::before {
    content: ""; position: absolute; left: 3px; top: 0; bottom: 0;
    width: 1px; background: var(--line);
}
.timeline .entry::after {
    content: ""; position: absolute; left: 0; top: 1.75rem;
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--volt);
}
.timeline .entry:first-of-type::before { top: 1.75rem; }
.timeline .entry:last-child::before { bottom: auto; height: 1.75rem; }
.timeline .entry h3 { margin: 0.1em 0 0.3em; font-size: 1.08rem; }

/* ------------------------------------------------------------ credit packs */

.packs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.pack {
    position: relative;
    display: flex; flex-direction: column;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius-lg); padding: 1.5rem 1.25rem 1.25rem;
    text-align: center;
}
.pack--popular { border-color: var(--volt); }

.pack__flag {
    position: absolute; top: 0; left: 50%; transform: translate(-50%, -50%);
    padding: 0.25em 0.8em; border-radius: 999px;
    background: var(--volt); color: var(--jungle);
    font-size: 0.68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em; white-space: nowrap;
}

.pack__credits {
    font-size: 2.6rem; font-weight: 700; line-height: 1;
    color: var(--volt); letter-spacing: -0.03em;
}
.pack__bonus { font-size: 1.2rem; color: var(--redline); vertical-align: super; }
.pack__label {
    font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--muted); margin-bottom: 0.9rem;
}
.pack__price { font-size: 1.5rem; font-weight: 700; }
.pack__each { font-size: 0.82rem; color: var(--muted); margin-bottom: 0.75rem; }
.pack__blurb { flex: 1; margin: 0 0 1rem; }
.pack .btn { margin-top: auto; }

/* =========================================================================
   Texture
   The app is a lot of dark rectangles. These give it depth without competing
   with content: a faint raptor-track trail over the page, and a soft light
   fall on the sidebar so the two planes read as separate surfaces.
   Everything here is decorative and sits behind content at very low contrast.
   ========================================================================= */

body {
    background-color: var(--jungle);
    background-image: url('/assets/img/raptor-tracks.svg');
    background-repeat: repeat;
    /* 300px keeps each print small enough to read as texture. Going larger to
       hide the repeat only made every print bigger and more noticeable, which
       is the opposite of the point -- the faintness does that work instead. */
    background-size: 300px 300px;
    background-attachment: fixed;   /* the trail stays put while content scrolls */
}

/* A jungle-floor vignette: slightly lighter at the top left, falling away to
   the corners, so a full-width page is not a flat slab. */
body::before {
    content: "";
    position: fixed; inset: 0; z-index: -1; pointer-events: none;
    background:
        radial-gradient(1100px 700px at 12% -10%, rgba(200, 241, 53, 0.10), transparent 60%),
        radial-gradient(900px 600px at 105% 8%, rgba(255, 107, 44, 0.06), transparent 62%);
}

/* The sidebar is a separate plane from the page, and it should look like one.
   Four layers, front to back:
     1. the same raptor trail as the page, at a smaller tile, so the panel
        belongs to the same world rather than being bolted onto it;
     2. a volt-green fall of light down from the top edge;
     3. a shadow gathering at the foot;
     4. the flat surface colour, which is what shows if a gradient or the SVG
        fails to load.
   Then a hairline of light down the inner border and a shadow cast onto the
   content column, so the panel reads as sitting above the page. */
.side {
    background-image:
        url('/assets/img/raptor-tracks.svg'),
        linear-gradient(180deg, rgba(200, 241, 53, 0.05) 0%, transparent 34%),
        linear-gradient(180deg, transparent 62%, rgba(0, 0, 0, 0.30) 100%);
    background-size: 240px 240px, auto, auto;
    background-repeat: repeat, no-repeat, no-repeat;
    box-shadow:
        inset -1px 0 0 rgba(200, 241, 53, 0.09),
        7px 0 26px rgba(0, 0, 0, 0.34);
}
/* Decoration must never fight the text on top of it, and the sidebar is dense
   with small labels -- so the trail is held back harder here than on the page.
   A wash over the tracks, under the content. */
.side::before {
    content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: linear-gradient(180deg,
        rgba(19, 30, 26, 0.62) 0%, rgba(16, 26, 22, 0.80) 100%);
}
.side > * { position: relative; z-index: 1; }

/* Cards lift off the textured ground rather than dissolving into it. */
.card, .statecard, .pack, .channel {
    background-color: var(--surface);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset,
                0 8px 24px rgba(0, 0, 0, 0.22);
}

@media@media (prefers-reduced-motion: reduce) {
    body { background-attachment: scroll; }
}

/* =========================================================================
   Small screens
   The trail is sized for a desktop page. At 375px a 300px tile puts one huge
   print per screenful, which reads as a motif rather than texture -- and it
   lands behind headings that sit directly on the background. Smaller tile,
   and it goes back to being ground.
   ========================================================================= */
@media (max-width: 640px) {
    body { background-size: 170px 170px; }
}


/* =========================================================================
   Toasts
   Every transient confirmation goes here. Native alert() blocks the page,
   looks like 1998, and cannot carry brand voice.
   ========================================================================= */

.toasts {
    position: fixed; z-index: 200;
    right: 1rem; bottom: 1rem;
    display: flex; flex-direction: column-reverse; gap: 0.6rem;
    max-width: min(380px, calc(100vw - 2rem));
    pointer-events: none;
}

.toast {
    display: flex; align-items: flex-start; gap: 0.7rem;
    padding: 0.85rem 1rem;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-left: 3px solid var(--volt);
    border-radius: var(--radius);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
    color: var(--offwhite);
    font-size: 0.92rem; line-height: 1.45;
    pointer-events: auto;
    animation: toastin .22s cubic-bezier(.2,.9,.3,1);
}
.toast--error { border-left-color: var(--redline); }
.toast--info  { border-left-color: var(--muted); }
.toast.is-going { animation: toastout .18s ease forwards; }

.toast__icon { flex-shrink: 0; width: 20px; height: 20px; margin-top: 1px; }
.toast__body { flex: 1; min-width: 0; }
.toast__close {
    flex-shrink: 0; background: none; border: 0; padding: 0 0 0 0.4rem;
    color: var(--muted); font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.toast__close:hover { color: var(--offwhite); }

@keyframes toastin  { from { opacity: 0; transform: translateY(10px) scale(.98); } }
@keyframes toastout { to   { opacity: 0; transform: translateY(6px);  } }

@media (max-width: 620px) {
    .toasts { right: 0.75rem; left: 0.75rem; bottom: 0.75rem; max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
    .toast, .toast.is-going { animation: none; }
}

/* =========================================================================
   Modals
   Built on <dialog>, so focus trapping, Escape, and inertness of the page
   behind come from the browser rather than from hand-written JS.
   ========================================================================= */

.modal {
    width: min(460px, calc(100vw - 2rem));
    padding: 0; border: 0; border-radius: var(--radius-lg);
    background: var(--surface);
    color: var(--offwhite);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6);
    border: 1px solid var(--line);
}
.modal::backdrop { background: rgba(5, 9, 8, 0.72); backdrop-filter: blur(2px); }

/* A browser without showModal() gets no ::backdrop and no automatic centring,
   so the fallback dialog is positioned by hand. Same box, same animation --
   only the scaffolding differs. */
.modal[data-fallback] {
    position: fixed; z-index: 90;
    top: 50%; left: 50%; transform: translate(-50%, -50%);
    margin: 0; display: block;
}
.modal[data-fallback]::before {
    content: ""; position: fixed; inset: 0; z-index: -1;
    background: rgba(5, 9, 8, 0.72);
}

.modal[open] { animation: modalin .18s cubic-bezier(.2,.9,.3,1); }
@keyframes modalin { from { opacity: 0; transform: translateY(8px) scale(.985); } }

.modal__inner { display: flex; gap: 1.1rem; padding: 1.5rem; }
.modal__art { width: 84px; height: 84px; flex-shrink: 0; }
.modal__text { flex: 1; min-width: 0; }
.modal__text h2 { font-size: 1.2rem; margin: 0 0 0.35em; }
.modal__text p  { margin: 0; color: var(--muted); font-size: 0.94rem; line-height: 1.5; }
.modal__actions {
    display: flex; justify-content: flex-end; gap: 0.6rem; flex-wrap: wrap;
    padding: 0 1.5rem 1.35rem;
}
.modal--danger .modal__text h2 { color: var(--redline); }

@media (max-width: 480px) {
    .modal__inner { flex-direction: column; align-items: flex-start; gap: 0.9rem; }
    .modal__actions { padding-bottom: 1.1rem; }
    .modal__actions .btn { flex: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .modal[open] { animation: none; }
}

/* --------------------------------------------------------- hours & fields */

.field-row {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0 1rem;
}

.hours { margin-bottom: 1.1rem; }
.hours__row {
    display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;
    padding: 0.5rem 0; border-bottom: 1px solid var(--line);
}
.hours__row:last-child { border-bottom: 0; }
.hours__day {
    width: 3em; flex-shrink: 0;
    font-weight: 700; font-size: 0.85rem; color: var(--muted);
    text-transform: uppercase; letter-spacing: 0.05em;
}
.hours input[type=time] {
    width: auto; margin: 0; padding: 0.4em 0.6em; font-size: 0.9rem;
    color-scheme: dark;   /* so the native time picker is not a white slab */
}
.hours input[type=time]:disabled { opacity: 0.35; }
.hours .switch { min-width: 7.5em; }

@media (max-width: 520px) {
    .hours__row { gap: 0.5rem; }
    .hours .switch { order: 3; }
}

/* ------------------------------------------------------ getting started */

.checklist-card__head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap; margin-bottom: 0.9rem;
}

.progress {
    height: 5px; border-radius: 999px; background: var(--surface-2);
    overflow: hidden; margin-bottom: 1.1rem;
}
.progress__bar {
    height: 100%; background: var(--volt); border-radius: 999px;
    transition: width .3s ease;
}

.tasklist { list-style: none; margin: 0; padding: 0; }
.tasklist__item {
    display: flex; align-items: flex-start; gap: 0.75rem;
    padding: 0.7rem 0; border-bottom: 1px solid var(--line);
}
.tasklist__item:last-child { border-bottom: 0; }
.tasklist__tick {
    flex-shrink: 0; width: 20px; height: 20px; margin-top: 1px;
    border: 1px solid var(--line); border-radius: 50%;
    display: grid; place-items: center;
    font-size: 0.72rem; color: var(--jungle);
}
.tasklist__item.is-done .tasklist__tick { background: var(--volt); border-color: var(--volt); }
.tasklist__item.is-done .tasklist__text > a,
.tasklist__item.is-done { color: var(--muted); }
.tasklist__text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.tasklist__blurb { font-size: 0.84rem; color: var(--muted); }
.tasklist__opt {
    display: inline-block; margin-left: 0.4em; padding: 0 0.45em;
    border: 1px solid var(--line); border-radius: 999px;
    font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted);
}

/* ---------------------------------------------------- mobile refinements */

/* Below this the label and the two switches cannot share a row without
   crushing the label into a three-line column. Stack instead. */
@media (max-width: 560px) {
    .toggle-row { flex-direction: column; gap: 0.6rem; }
    .toggle-row__controls { width: 100%; gap: 1.5rem; }
    .switch__label { min-width: 0; }
}

/* Tap targets: 44px is the floor for anything a thumb has to hit.
   Buttons, form controls and navigation -- not links inside prose. Giving
   every inline link a 44px box would wreck the line spacing of the sentence
   around it, and a link in a sentence is not a tap target in the sense the
   guideline means. */
@media (max-width: 900px) {
    .btn { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
    /* --sm is a smaller button, not a smaller target. */
    .btn--sm { min-height: 44px; }
    .btn--full { display: flex; }
    .side__link, .side__credits, .side__install { min-height: 44px; }
    /* The admin nav is a row of tabs, which is navigation. */
    .adminbar a { min-height: 44px; display: inline-flex; align-items: center; }
    .toast__close { min-width: 44px; min-height: 44px; }
    /* A checkbox is a 13px box however it is styled, so the label around it
       carries the target instead. */
    .checks label, label.check { min-height: 44px; display: flex; align-items: center; }
    input[type="text"], input[type="email"], input[type="password"],
    input[type="number"], input[type="search"], input[type="time"],
    input[type="url"], input[type="tel"], select, textarea { min-height: 44px; }
    /* The checklist's task links sit above their own description, so giving
       them a 44px BOX would space the whole list out. Negative margin against
       the padding grows the hit area without moving anything on the page. */
    .tasklist__text a { display: inline-block; padding: 0.7rem 0; margin: -0.7rem 0; }
    /* The checklist card's collapse control is a control like any other. */
    .checklist-card summary { min-height: 44px; display: flex; align-items: center; }
    .switch__track { width: 46px; height: 26px; }

    .switch input:checked ~ .switch__track .switch__thumb { transform: translateX(20px); }
}

/* Wide content scrolls inside its own box rather than pushing the page out. */
.channel__body { overflow-x: auto; }
table { display: block; overflow-x: auto; max-width: 100%; }

/* =========================================================================
   R2 -- dashboard, referrals and the hunt archive
   Written alongside includes/dashboard.php, public/credits.php and
   public/playbook.php. Kept here rather than in three page-local <style>
   blocks because these are member-facing screens: the stylesheet is
   downloaded once and cached, three inline blocks are not.
   ========================================================================= */
/* =========================================================================
   Hunting Grounds dashboard  (includes/dashboard.php)

   Two families here. Tiles are DATA: flat, bordered, no shadow, so they read
   as readouts rather than as more cards. Panels reuse .card and sit below the
   hunt list, where they can afford the height.
   ========================================================================= */

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

.tiles {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}
/* minmax(0,1fr) rather than 1fr: a 1fr track floors at min-content, so one
   long sub-line would widen its column and knock the others out of line. */
.tiles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 0; }

.tile {
    padding: 0.7rem 0.85rem;
    background: var(--jungle);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    min-width: 0;
}
.tile__n {
    font-size: 1.6rem; font-weight: 700; line-height: 1.05;
    color: var(--volt);
    /* Proportional figures on purpose: tabular-nums gives every digit the
       width of a 0, which makes a number like 121 look loose at this size. */
}
.tile__n--quiet { color: var(--muted); }
.tile__l {
    margin-top: 0.25rem;
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted);
}
.tile__sub { margin-top: 0.15rem; font-size: 0.78rem; color: var(--muted); }

/* ------------------------------------------------------- Rev's watching -- */

.watch h2 { margin-bottom: 0.25em; }
.watch__lede { margin: 0 0 0.9rem; }

.watch__subhead {
    margin: 1.25rem 0 0;
    font-size: 0.72rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted);
}

.watchlist { list-style: none; margin: 0; padding: 0; }
.watchlist__item { padding: 0.75rem 0; border-bottom: 1px solid var(--line); }
.watchlist__item:last-child { border-bottom: 0; padding-bottom: 0; }
.watchlist__meta {
    display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;
    margin-bottom: 0.35rem;
    font-size: 0.78rem; color: var(--muted);
}
.watchlist__title { font-weight: 600; line-height: 1.35; }

/* How strongly Rev rates a signal. The unfilled track is a step off the
   surface rather than a different hue, so the state reads across the bar. */
.meter {
    display: block; max-width: 180px; height: 3px; margin-top: 0.5rem;
    background: var(--surface-2); border-radius: 999px; overflow: hidden;
}
.meter__fill { display: block; height: 100%; background: var(--volt); border-radius: 999px; }

/* Grid rather than a flex row: it wraps on a narrow screen instead of hiding
   days behind a horizontal scroll nobody discovers. */
.week {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
    gap: 0.5rem; list-style: none; margin: 0.75rem 0 0; padding: 0;
}
.week__day {
    display: flex; flex-direction: column; gap: 0.1rem;
    padding: 0.5rem 0.6rem;
    background: var(--jungle);
    border: 1px solid var(--line); border-left-width: 3px;
    border-radius: var(--radius);
    min-width: 0;
}
.week__name { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.week__cond { font-weight: 600; font-size: 0.9rem; }
.week__temp { font-size: 0.8rem; color: var(--muted); }

/* Green is the booking window, orange is an extreme, grey is weather that
   simply makes cars dirty. */
.week__day--clear  { border-left-color: var(--volt); }
.week__day--heat,
.week__day--freeze { border-left-color: var(--redline); }
.week__day--rain,
.week__day--snow   { border-left-color: var(--muted); }

/* -------------------------------------------------------- CRM snapshot -- */

.crmsnap__head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;
}
.crmsnap__head h2 { margin: 0; }
.crmsnap__tags { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.crmsnap__foot { margin: 0.9rem 0 0; }

/* -------------------------------------------------------------- charts -- */

.charts {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1rem; margin-bottom: 1rem;
}

.chart {
    margin: 0; padding: 1.25rem 1.5rem;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    min-width: 0;
}
.chart__head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1rem;
}
.chart__head h3 { margin: 0; }

/* The cap is what keeps the bars honest. The SVG stretches to its container,
   so without a ceiling a 24-unit bar would render 50px thick on a wide card.
   The inline max-width comes from the chart's own viewBox width. */
.chart__plotwrap { width: 100%; }
.chart__plot { display: block; width: 100%; height: 120px; }

.chart__base { stroke: var(--line); stroke-width: 1; }

.chart__bar { fill: var(--volt); }
.chart__bar--zero { fill: var(--muted); opacity: 0.3; }
/* The newest period is still running, so it is dimmed rather than emphasised:
   a partial week drawn at full strength reads as a decline that has not
   happened. Declared after --zero so an empty current period takes this. */
.chart__bar--part { opacity: 0.5; }

/* A transparent fill is still a painted fill, so it takes the hover; fill:none
   would not. This gives the whole band a target rather than the thin bar. */
.chart__hit { fill: transparent; }
.chart__band:hover .chart__hit { fill: var(--surface-2); }

.chart__axis {
    display: flex; justify-content: space-between;
    margin-top: 0.4rem; font-size: 0.75rem; color: var(--muted);
}

.chart__data { margin-top: 0.9rem; font-size: 0.85rem; }
.chart__data > summary { padding: 0.3rem 0; color: var(--muted); cursor: pointer; }
.chart__data > summary:hover { color: var(--offwhite); }
/* Overrides the global table{display:block} scroll hack. These two columns
   are short and must actually share the width; nothing here can overflow. */
.chart__data table {
    display: table; width: 100%; margin-top: 0.5rem; border-collapse: collapse;
}
.chart__data th, .chart__data td {
    padding: 0.3rem 0; border-bottom: 1px solid var(--line);
    font-weight: 400; text-align: left;
}
.chart__data th { color: var(--muted); }
.chart__data td { text-align: right; font-variant-numeric: tabular-nums; }
.chart__data tr:last-child th, .chart__data tr:last-child td { border-bottom: 0; }

/* ------------------------------------------------------- small screens -- */

@media (max-width: 620px) {
    .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* Three tiles in two columns leaves an orphan, so the last one spans. */
    .tiles--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .tiles--3 .tile:last-child { grid-column: 1 / -1; }

    .tile { padding: 0.6rem 0.7rem; }
    .tile__n { font-size: 1.35rem; }

    .chart { padding: 1rem 1.1rem; }
    .chart__plot { height: 96px; }
}

/* A disclosure control is a control, so it gets a thumb-sized target like
   every other one. Padding rather than display:flex, which would take the
   marker with it. */
@media (max-width: 900px) {
    .chart__data > summary { padding: 0.65rem 0; }
}

/* ------------------------------------------------------------------ referrals */

/* One row per shop somebody sent us. The state is a .tag, which already carries
   its own colour, so these rules only lay the row out and rule it off -- there
   is no second colour vocabulary here to keep in step with the first. */
.reflist { margin: 0; }

.reflist__row {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    padding: 0.55em 0; border-bottom: 1px solid var(--line);
}
.reflist__row:last-child { border-bottom: 0; }

/* A masked address has no spaces in it, so it needs somewhere to break --
   without this one long referral drags the card wider than the column. */
.reflist__who { flex: 1; min-width: 0; font-size: 0.92rem; overflow-wrap: anywhere; }

.reflist__when { margin-left: auto; white-space: nowrap; }

/* --------------------------------------------------- archived / missed hunts */

/* The archive sits under the live list and has to read as secondary without
   becoming unreadable, so it is dimmed at rest and full strength on hover --
   a member who has scrolled this far is deliberately looking at it. */
.archive { margin-top: 2.5rem; }

.archive__head {
    display: flex; align-items: baseline; gap: 0.75rem;
    flex-wrap: wrap; margin-bottom: 0.4rem;
}

/* Redline because a growing pile of missed opportunities is a real signal.
   The copy underneath is what keeps it information rather than a telling-off. */
.archive__count {
    font-size: 0.8rem; font-weight: 600; color: var(--redline);
    text-transform: uppercase; letter-spacing: 0.05em;
}

/* Not a .card--link: the restore form lives inside, and a <form> cannot sit in
   an <a>. So the title carries the link instead, and it borrows the hover
   colour .card--link:hover .hunt__title would have given it. */
.card--archived { opacity: 0.72; transition: opacity .12s; }
.card--archived:hover { opacity: 1; }
.card--archived .hunt__title a { color: var(--offwhite); }
.card--archived .hunt__title a:hover { color: var(--volt); text-decoration: none; }

.archive__actions {
    display: flex; align-items: center; gap: 0.75rem;
    flex-wrap: wrap; margin-top: 0.9rem;
}

.tag--missed { border-color: var(--line); color: var(--muted); }
