/* Chain Collector — public site.
   Separate from admin.css on purpose: the panel is a tool for one person, this
   is the front door. Shares only the palette, so the two read as one product. */

:root {
    --green: #3B7A57;
    --green-dark: #2c5c41;
    --ink: #1c1f1d;
    --muted: #5f6b64;
    --line: #dfe3e0;
    --danger: #b00020;
    --bg: #fbfbfa;
}

* { box-sizing: border-box; }

body {
    font-family: system-ui, -apple-system, "Hiragino Kaku Gothic ProN", "Noto Sans JP", sans-serif;
    margin: 0;
    color: var(--ink);
    background: var(--bg);
    line-height: 1.55;
}

/* --- chrome ------------------------------------------------------------- */

.site-head {
    background: var(--green);
    color: #fff;
    padding: .85em 1.2em;
    display: flex;
    gap: 1em;
    align-items: center;
    flex-wrap: wrap;
}

.brand {
    color: #fff;
    text-decoration: none;
    font-weight: 700;
    font-size: 1.15em;
    letter-spacing: .01em;
}

.site-lang { margin-left: auto; display: flex; gap: .6em; font-size: .9em; }
.site-lang a { color: #fff; opacity: .85; text-decoration: none; }
.site-lang a:hover { opacity: 1; text-decoration: underline; }
.site-lang .is-current { font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

/* Sign-in state sits between the brand and the language switcher; the
   switcher keeps its margin-left:auto, so this group stays left of it. */
.site-account {
    display: flex;
    align-items: center;
    gap: .75em;
    margin-left: 1em;
    font-size: .9em;
}
.site-account a { color: #fff; opacity: .85; text-decoration: none; }
.site-account a:hover { opacity: 1; text-decoration: underline; }
.site-user { font-weight: 600; }
.site-account form { margin: 0; }

/* A button that has to read as a link: log out must be a POST, but it should
   not look like a call to action next to the brand. */
.linkish {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: #fff;
    opacity: .85;
    cursor: pointer;
    text-decoration: none;
}
.linkish:hover { opacity: 1; text-decoration: underline; }

main {
    max-width: 1100px;
    margin: 0 auto;
    padding: 1.5em 1.2em 3em;
}

.tagline { color: var(--muted); margin: 0 0 1.4em; }

.site-foot {
    border-top: 1px solid var(--line);
    padding: 1.4em 1.2em 2.4em;
    color: var(--muted);
    font-size: .85em;
}
.site-foot p { max-width: 1100px; margin: .3em auto; }

/* --- filters ------------------------------------------------------------ */

.filters {
    display: flex;
    flex-wrap: wrap;
    gap: .75em 1em;
    align-items: flex-end;
    padding: 1em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 8px;
    margin-bottom: 1em;
}

.filters label {
    display: flex;
    flex-direction: column;
    gap: .25em;
    font-size: .85em;
    color: var(--muted);
}

.filters select,
.filters input[type="search"] {
    min-width: 12em;
    padding: .45em .5em;
    border: 1px solid var(--line);
    border-radius: 5px;
    background: #fff;
    color: var(--ink);
    font: inherit;
    font-size: .95rem;
}

.filters button {
    padding: .5em 1.1em;
    border: 0;
    border-radius: 5px;
    background: var(--green);
    color: #fff;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.filters button:hover { background: var(--green-dark); }

.link-button {
    padding: .5em .6em;
    color: var(--muted);
    text-decoration: none;
    font-size: .9em;
}
.link-button:hover { text-decoration: underline; }

/* --- map ---------------------------------------------------------------- */

.count-line { margin: 0 0 .6em; font-size: .9em; }
.muted { color: var(--muted); }
.empty { color: var(--muted); font-style: italic; }

.map {
    height: min(68vh, 700px);
    min-height: 340px;
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
    background: #eee;
}

/* Leaflet stacks its panes high by default; keep them under the header so
   popups and zoom controls cannot cover the site navigation. */
.map .leaflet-pane,
.map .leaflet-control { z-index: 1; }

/* --- one chain in one country ------------------------------------------- */

/* Shorter than the browse map: this one is a companion to the list below it,
   not the page itself, and a full-height map would push the list off screen. */
.map-collection {
    height: min(44vh, 420px);
    min-height: 260px;
    margin-top: 1.2em;
}

.crumb { margin: 0 0 .4em; font-size: .88em; }
.crumb a { color: var(--green-dark); }

/* Every meter is a link now, so it has to look clickable without turning the
   progress section into a wall of blue: the name underlines on hover and
   takes the ink colour the heading already had. */
.meter-link { color: inherit; text-decoration: none; }
.meter-link:hover { text-decoration: underline; text-underline-offset: 2px; }
.meter-link:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

.branch-list {
    list-style: none;
    padding: 0;
    margin: 1em 0 0;
    counter-reset: branch;
}
.branch-list li {
    display: flex;
    align-items: baseline;
    gap: .7em;
    padding: .55em .4em;
    border-bottom: 1px solid var(--line);
    scroll-margin-top: 5em;
}
.branch-list li:last-child { border-bottom: 0; }

/* A pin click flashes its row. Colour, then fade back — the highlight is an
   answer to "which one is that", not a state the row is now in. */
.branch-list li.is-highlit {
    background: #eef6f1;
    transition: background 1.2s ease;
}

.branch-num {
    min-width: 2em;
    font-size: .85em;
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.branch-where { flex: 1; }
.branch-where .muted { display: block; font-size: .85em; }
.branch-visits {
    display: flex;
    align-items: baseline;
    gap: .5em;
    font-size: .85em;
    white-space: nowrap;
}

.visit-badge {
    padding: 0 .45em;
    border-radius: 999px;
    background: #eef6f1;
    color: var(--green-dark);
    font-weight: 600;
}

@media (max-width: 560px) {
    .branch-list li { flex-wrap: wrap; }
    .branch-visits { margin-left: 2.7em; }
}

.pill-closed {
    display: inline-block;
    padding: .05em .5em;
    border-radius: 999px;
    background: #fdecef;
    color: var(--danger);
    font-size: .85em;
}

/* --- chain list --------------------------------------------------------- */

.chain-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: .6em;
}

.chain-grid a {
    display: block;
    padding: .7em .85em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 7px;
    text-decoration: none;
    color: var(--ink);
}
.chain-grid a:hover { border-color: var(--green); }

.chain-grid .is-current a {
    border-color: var(--green);
    box-shadow: inset 0 0 0 1px var(--green);
}

.chain-name { display: block; font-weight: 600; }
/* The list's meta line is indented to clear the mark, so the two lines of a
   card read as one block rather than stepping back out to the left. */
.chain-grid .chain-meta { margin-left: calc(22px + .45em); }
.chain-meta { display: block; font-size: .82em; color: var(--muted); margin-top: .15em; }

/* --- narrow screens ----------------------------------------------------- */

@media (max-width: 560px) {
    .filters { padding: .8em; }
    .filters label,
    .filters select,
    .filters input[type="search"] { width: 100%; min-width: 0; }
    .filters button { width: 100%; }
    .map { height: 60vh; }
}

/* --- sign in / sign up -------------------------------------------------- */

.auth-card {
    max-width: 26em;
    margin: 1em auto 3em;
    padding: 1.6em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 10px;
}

.auth-card h1 { margin: 0 0 .3em; font-size: 1.35em; }
.auth-card .muted { color: var(--muted); margin-top: 0; }

.auth-form { display: flex; flex-direction: column; gap: 1em; margin-top: 1.4em; }
.auth-form label { display: flex; flex-direction: column; gap: .3em; font-weight: 600; }
.auth-form input {
    padding: .6em .7em;
    border: 1px solid var(--line);
    border-radius: 6px;
    font: inherit;
    /* 16px minimum, or iOS Safari zooms the whole page on focus. */
    font-size: 1rem;
}
.auth-form input:focus { outline: 2px solid var(--green); outline-offset: 1px; }
.auth-form small { font-weight: 400; }

.auth-form button {
    padding: .7em 1em;
    border: 0;
    border-radius: 6px;
    background: var(--green);
    color: #fff;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.auth-form button:hover { background: var(--green-dark); }

.auth-alt { margin: 1.3em 0 0; font-size: .9em; }
.auth-alt a { color: var(--green-dark); }

.flash {
    margin: 1em 0 0;
    padding: .7em .9em;
    border-radius: 6px;
    font-size: .92em;
}
.flash-error { background: #fdecef; color: var(--danger); border: 1px solid #f3c3cd; }
.flash-ok    { background: #eef6f1; color: var(--green-dark); border: 1px solid #c4ded1; }

/* --- check-in, inside a map popup --------------------------------------- */

.pin-popup .pin-actions {
    margin-top: .7em;
    /* Tally above the button rather than beside it: a Leaflet popup is narrow,
       and "Visited 4 times" next to a button wraps into a mess. */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .5em;
}

.checkin-button {
    padding: .4em .8em;
    border: 0;
    border-radius: 6px;
    background: var(--green);
    color: #fff;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.checkin-button:hover:not(:disabled) { background: var(--green-dark); }
.checkin-button:disabled { background: var(--muted); cursor: default; }

.pill-visited {
    display: inline-block;
    padding: .05em .6em;
    border-radius: 999px;
    /* Matches FILL_VISITED on the map, so the badge and the pin agree. */
    background: #f1e9fe;
    color: #5b21b6;
    font-size: .85em;
    font-weight: 600;
}

.pin-note { margin-top: .45em; font-size: .85em; }

/* --- profile & progress -------------------------------------------------- */

.profile-head { margin-bottom: 1.6em; }
.profile-head h1 { margin: 0 0 .15em; font-size: 1.5em; }
.profile-head p { margin: 0; font-size: .92em; }

.profile-section { margin-top: 2.4em; }
.profile-section h2 { font-size: 1.1em; margin: 0 0 .2em; }
.profile-section > .muted { margin-top: 0; font-size: .88em; }

.since-line { margin: .9em 0 0; font-size: .88em; }

.empty-state {
    padding: 2em 1.4em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 10px;
    text-align: center;
    color: var(--muted);
}
.empty-state a { color: var(--green-dark); margin-left: .4em; }

/* KPI row. Four headline numbers that share no unit, so they are tiles and
   not a chart inviting comparison between them. */
.stat-row {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: .8em;
}

.stat-tile {
    padding: 1em 1.1em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 10px;
}

.stat-label {
    display: block;
    font-size: .82em;
    color: var(--muted);
    margin-bottom: .25em;
}

.stat-value {
    display: block;
    font-size: 2em;
    font-weight: 600;
    line-height: 1.1;
    /* Proportional figures on purpose: tabular-nums gives every digit the
       width of a 0, which reads loose at this size. Columns get it instead. */
}

/* The mark in front of a chain's name — a logo where one exists, a monogram
   chip where it does not. Both are the same 22px box, so a mixed list keeps
   one rhythm and the names stay on one left edge. */
.chain-icon {
    display: inline-block;
    width: 22px;
    height: 22px;
    margin-right: .45em;
    /* Letterboxed, never cropped: Yoshinoya's mark is 1.7:1 and Quick's is
       taller than it is wide, and cropping either to a square would cut the
       part that identifies it. */
    object-fit: contain;
    /* Sits on the text baseline rather than hanging below it. */
    vertical-align: -.35em;
}

.chain-icon-mono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    /* The hue comes from the chain's name, so a chain is the same colour on
       every page. Colour means "which chain" here and nowhere else on this
       page — the meters below stay on the single green. */
    background: hsl(var(--mono-hue, 150) 40% 89%);
    color: hsl(var(--mono-hue, 150) 45% 27%);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: .01em;
    /* Fixed, so a two-letter monogram is not smaller than a one-letter one
       just because the heading around it is a different size. */
    font-family: system-ui, sans-serif;
}

/* One chain and the countries it is collected in.

   Each chain is its own card. Run as plain blocks on one background they read
   as a single long list of meters, and the question this section answers —
   "how far through McDonald's am I" — then starts with working out where
   McDonald's ends and Starbucks begins. A border and a white panel per chain
   make that boundary the first thing the eye gets, before any number. */
.chain-cards {
    display: grid;
    gap: .9em;
    margin-top: 1.1em;
    /* Each card keeps its own height. Stretching them to match would give a
       chain collected in one country the same visual weight as one collected
       in six, which is the opposite of what this section is measuring. */
    align-items: start;
}
/* Two columns once there is room for them. Below this the cards are narrow
   enough that a meter and its numbers start wrapping, so it stays one. */
@media (min-width: 720px) {
    .chain-cards { grid-template-columns: 1fr 1fr; }
}

.chain-block {
    padding: .95em 1.1em 1.05em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 10px;
}

.chain-block-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: .3em 1em;
    padding-bottom: .5em;
    border-bottom: 1px solid var(--line);
}
/* The chain's name is the card's one label, so it carries a little more weight
   than the country rows beneath it — the only hierarchy in here. */
.chain-block-head h3 { margin: 0; font-size: 1.05em; font-weight: 700; }
.chain-total { font-size: .85em; }
.chain-total strong { color: var(--ink); }

/* The country rows sit under their chain, indented just enough to read as
   belonging to it without becoming a nested list the eye has to parse. */
.chain-block .meter-list { margin-top: .8em; }
.chain-block .meter-row + .meter-row { margin-top: .9em; }

/* A chain collected in one country is a single line: the country rides in the
   title, so there is no heading with one lonely row beneath it. The card is
   the same width and border as the nested ones, which is what keeps a mixed
   list from looking like two different sections. */
.chain-block-solo { padding-bottom: .95em; }
.chain-block-solo .meter-head h3 { margin: 0; font-size: 1.05em; font-weight: 700; }
.chain-country { font-weight: 400; color: var(--muted); }
.chain-country::before { content: "· "; }

/* Meters. Each row is one ratio against its own limit, so the fill is the
   brand hue and the track a light step of the same hue — state reads across
   the whole bar rather than only where the fill ends. */
.meter-list { list-style: none; padding: 0; margin: 1.1em 0 0; }
.meter-row + .meter-row { margin-top: 1.1em; }

.meter-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1em;
    margin-bottom: .35em;
}

.meter-name { font-weight: 600; }

.meter-value {
    font-size: .9em;
    color: var(--muted);
    /* A column of numbers down the right edge, so these DO align. */
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.meter-value strong { color: var(--ink); }
.meter-pct { margin-left: .5em; color: var(--green-dark); font-weight: 600; }

.meter {
    height: 10px;
    background: #e3ede7;
    border-radius: 999px;
    overflow: hidden;
}

.meter-fill {
    display: block;
    height: 100%;
    background: var(--green);
    /* Square where it starts, rounded at the data end. */
    border-radius: 0 999px 999px 0;
    /* A floor in pixels, not percent. A percentage floor would paint 0.4% and
       4% at the same length and quietly overstate the smaller one; 3px is
       just enough that a real visit never renders as nothing. */
    min-width: 3px;
}

.meter-note { margin: .35em 0 0; font-size: .82em; }

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

.stat-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 1em;
    font-size: .92em;
}
.stat-table th,
.stat-table td {
    text-align: left;
    padding: .55em .6em;
    /* Hairline, solid, recessive — the rows are the data, not the rules. */
    border-bottom: 1px solid var(--line);
}
.stat-table th { font-size: .82em; color: var(--muted); font-weight: 600; }
.stat-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.stat-table tbody tr:hover { background: #f6f8f7; }

/* --- achievements -------------------------------------------------------- */

.badge-grid {
    list-style: none;
    padding: 0;
    margin: 1.1em 0 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: .7em;
}

.badge {
    padding: .8em .9em;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 8px;
    /* Tier rides on a left edge, and never on colour alone — the tier word is
       not the only thing carrying it; title and description are always there. */
    border-left: 4px solid var(--line);
}
.badge-bronze    { border-left-color: #a2703f; }
.badge-silver    { border-left-color: #8c9298; }
.badge-gold      { border-left-color: #c8a020; }
.badge-legendary { border-left-color: #7c3aed; }

.badge-title { display: block; font-weight: 600; }
.badge-desc  { display: block; font-size: .85em; color: var(--muted); margin-top: .1em; }
.badge-date  { display: block; font-size: .78em; margin-top: .35em; }

/* --- visit history ------------------------------------------------------- */

.visit-list { list-style: none; padding: 0; margin: 1em 0 0; }
.visit-list li {
    display: flex;
    flex-wrap: wrap;
    gap: .2em .8em;
    align-items: baseline;
    padding: .55em 0;
    border-bottom: 1px solid var(--line);
}
.visit-date { font-size: .85em; min-width: 7.5em; font-variant-numeric: tabular-nums; }
.visit-where { flex: 1; min-width: 12em; }
.visit-place { font-size: .85em; }

/* --- Swarm import -------------------------------------------------------- */

.import-upload {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .7em;
    margin-top: 1em;
}

.import-upload label { font-weight: 600; width: 100%; }
.import-upload input[type="file"] { font: inherit; font-size: .9em; flex: 1; min-width: 14em; }

.import-upload button,
.import-actions button {
    font: inherit;
    font-weight: 600;
    padding: .55em 1.1em;
    border: 0;
    border-radius: 6px;
    background: var(--green);
    color: #fff;
    cursor: pointer;
}

.import-upload button:hover,
.import-actions button:hover { background: var(--green-dark); }

.import-note { margin: .8em 0 0; font-size: .85em; }
.import-foot { margin-top: 1.4em; font-size: .88em; }

/* The match list. Long, so the tick column is the first thing on the row and
   the whole venue name is a label for it — the target is the sentence, not a
   13px square. */
.import-table td { vertical-align: top; }
.import-table .tick { width: 2.2em; padding-top: .8em; }
.import-table .tick input { width: 1.1em; height: 1.1em; }
.import-table .when { white-space: nowrap; font-size: .85em; color: var(--muted); }
.import-table label { cursor: pointer; }

/* A row that needs a decision is marked, not coloured in: it is not a warning,
   it is the one place the page is asking rather than telling. */
.row-ambiguous { background: #fbf8ef; }
.row-ambiguous td { border-left: 0; }
.ambiguous-note { margin: 0 0 .3em; font-size: .85em; }

.choice { display: block; font-size: .9em; padding: .12em 0; }
.choice input { margin-right: .45em; }
.choice-done { color: var(--muted); }

/* Rows already in the collector's history. Receded rather than hidden: a row
   that disappeared between two runs of the same import would read as a match
   that got lost. Nothing here is actionable, so nothing here competes with
   the rows that are. */
.row-imported { color: var(--muted); }
.row-imported strong,
.row-imported .when { color: var(--muted); }
.tick-done { color: var(--green); font-weight: 700; }

.tag-imported {
    display: inline-block;
    margin-left: .4em;
    padding: 0 .45em;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: #fff;
    font-size: .75em;
    font-weight: 600;
    color: var(--muted);
    white-space: nowrap;
    /* Sits on the baseline of the venue name rather than after the address, so
       one glance down the column finds every one of them. */
    vertical-align: baseline;
}

.import-actions {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: 1.2em;
    margin-top: 1.5em;
    padding: .9em 0;
    background: var(--bg);
    border-top: 1px solid var(--line);
}

.import-actions a { color: var(--green-dark); font-size: .9em; }

/* Visible to a screen reader, not on screen: the tick column's heading, which
   has no room for a word but still needs one. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* --- narrow screens, for the rules above -------------------------------- */

@media (max-width: 560px) {
    /* Below the brand rather than beside it: three groups in one row leaves
       nothing room to breathe once a display name is in the middle one. */
    .site-account { margin-left: 0; order: 3; width: 100%; }
    .auth-card { padding: 1.2em; border-radius: 8px; }
    .stat-value { font-size: 1.7em; }
    .visit-date { min-width: 0; }
    /* The meter's numbers drop under its name rather than squeezing beside it. */
    .meter-head { flex-direction: column; gap: .1em; }
    /* The match table keeps its tick and its venue; the distance column is the
       one a phone can lose without losing the decision. */
    .import-table .num { display: none; }
    .import-upload button { width: 100%; }
    /* The card keeps its border on a phone; only the air inside it gives way. */
    .chain-block { padding: .8em .85em .9em; }
}
