/* ChloroFile shared styles.
   Tokens mirror the app's design system so the site and the product read as
   one thing: dark only, purple-violet accent, ambient glow. */

:root {
    --page: #0a0a0a;
    --card: #111111;
    --elevated: #161616;
    --border: #1e1e1e;
    --border-hover: #2a2a2a;

    --purple: #8b5cf6;
    --purple-light: #a78bfa;
    --purple-highlight: #c084fc;
    --glow: #e9d5ff;
    --violet: #a855f7;
    --indigo: #818cf8;

    --text: #ffffff;
    /* Evenly spaced and all clearing 4.5:1 on the darkest panel they sit on.
       --text-subtle was #666666, which is 3.15 there: it set the notes, the
       breadcrumbs, the footer and the station citations, so it was most of the
       contrast failures on the site by itself. --text-muted moved with it to
       keep the three steps apart. */
    --text-body: #aaaaaa;     /* 7.79 on --elevated */
    --text-muted: #969696;    /* 6.12 */
    --text-subtle: #7f7f7f;   /* 4.52 */

    --success: #22c55e;
    --cyan: #60a5fa;
    /* Flowering, and the frost that ends it. The ribbon is the only
       thing on the site that needs a warm and a warning colour. */
    --sun: #f0a500;
    --alert: #ef4444;

    --max: 1080px;
    --radius: 16px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* The header is sticky, so anchored sections must stop clear of it rather
   than sliding underneath. */
:target, section[id] { scroll-margin-top: 84px; }

body {
    margin: 0;
    background: var(--page);
    color: var(--text);
    font: 400 17px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* The app's signature ambient glow, fixed behind everything. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(70rem 45rem at 50% -8%, rgba(139, 92, 246, 0.16), transparent 68%),
        radial-gradient(45rem 30rem at 88% 8%, rgba(129, 140, 248, 0.07), transparent 70%);
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 24px; }
.narrow { max-width: 760px; }

a { color: var(--purple-light); text-decoration: none; }
a:hover { color: var(--purple-highlight); text-decoration: underline; }

/* ---------------------------------------------------------------- header */

header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: rgba(10, 10, 10, 0.72);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    border-bottom: 1px solid var(--border);
}

.nav {
    display: flex;
    align-items: center;
    gap: 28px;
    height: 64px;
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 700;
    color: var(--text);
    margin-right: auto;
}
.brand:hover { text-decoration: none; }
.brand img { width: 30px; height: 30px; border-radius: 8px; }

.nav a.link { color: var(--text-body); font-size: 15px; }
.nav a.link:hover { color: var(--text); text-decoration: none; }

@media (max-width: 640px) {
    /* Five links and the wordmark need about 500px and a phone gives 327, so
       the row used to push the whole document sideways: every section on the
       site could be dragged 120px to the left, which reads as the page being
       broken rather than as a menu being too long. The overflow now belongs to
       the nav, which scrolls on its own and leaves the body still. */
    .nav {
        gap: 18px;
        overflow-x: auto;
        /* A scrollbar sitting under a 64px sticky bar is all cost and no
           information; the row is visibly cut off, which is the affordance. */
        scrollbar-width: none;
        -ms-overflow-style: none;
    }
    .nav::-webkit-scrollbar { display: none; }

    /* auto would push the links to the far end of the scrollable width rather
       than to the right of the wordmark, leaving a gap you have to scroll
       across to find them. */
    .brand { margin-right: 4px; }

    /* Without this the links compress towards illegibility instead of
       overflowing, which is the thing being fixed. */
    .nav .brand, .nav a.link { flex: none; }
    .nav a.link { font-size: 14px; }
}

/* ------------------------------------------------------------------ type */

h1 {
    font-size: clamp(40px, 7vw, 68px);
    line-height: 1.05;
    letter-spacing: -0.02em;
    font-weight: 800;
    margin: 0 0 20px;
}

h2 {
    font-size: clamp(28px, 4vw, 38px);
    line-height: 1.15;
    letter-spacing: -0.015em;
    font-weight: 800;
    margin: 0 0 16px;
}

h3 { font-size: 19px; font-weight: 700; margin: 0 0 8px; }

p { color: var(--text-body); margin: 0 0 16px; }

.eyebrow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--purple-light);
    text-shadow: 0 0 10px rgba(167, 139, 250, 0.55);
    margin-bottom: 14px;
}

.lede { font-size: 20px; color: var(--text-body); max-width: 640px; }

/* ------------------------------------------------------------------ hero */

.hero { padding: 90px 0 70px; text-align: center; }
.hero .lede { margin-left: auto; margin-right: auto; }

/* The artwork alone, lifted off its app-icon tile. No border, radius, or box
   shadow: those are what made it read as an icon sitting on the page rather
   than as the mark itself. The glow comes from the drawing. */
.hero-mark {
    width: 300px;
    height: auto;
    margin-bottom: 26px;
    /* The artwork carries its own neon; an extra glow only muddies it. */
}

@media (max-width: 640px) {
    .hero-mark { width: 228px; }
}

.grad {
    background: linear-gradient(100deg, var(--glow), var(--purple-highlight) 45%, var(--violet));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

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

.actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 32px; }

.btn {
    display: inline-block;
    padding: 13px 28px;
    border-radius: 12px;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    cursor: pointer;
}
.btn:hover { text-decoration: none; }

/* The app's .btn-glass-purple, translated back to the web it came from. */
.btn-primary {
    color: var(--glow);
    background: rgba(139, 92, 246, 0.20);
    border: 1px solid transparent;
    background-image:
        linear-gradient(rgba(139, 92, 246, 0.20), rgba(139, 92, 246, 0.20)),
        linear-gradient(to bottom, rgba(233, 213, 255, 0.95), rgba(192, 132, 252, 0.8) 25%, rgba(139, 92, 246, 0.45));
    background-origin: border-box;
    background-clip: padding-box, border-box;
    /* Two wide halos read as a light fitting rather than a button. The
       purple edge does the brand work; a real shadow does the lifting. */
    box-shadow: 0 0 14px rgba(168, 85, 247, 0.22), 0 6px 20px rgba(0, 0, 0, 0.45);
    transition: box-shadow 0.2s ease, filter 0.2s ease;
}
.btn-primary:hover {
    color: var(--glow);
    box-shadow: 0 0 20px rgba(168, 85, 247, 0.38), 0 10px 26px rgba(0, 0, 0, 0.5);
    filter: brightness(1.08) saturate(1.15);
}

.btn-secondary {
    color: var(--text);
    background: var(--elevated);
    border: 1px solid var(--border-hover);
    transition: border-color 0.2s ease, background 0.2s ease;
}
.btn-secondary:hover { border-color: rgba(139, 92, 246, 0.45); background: #1b1b1b; color: var(--text); }

.note { font-size: 13px; color: var(--text-subtle); margin-top: 18px; }

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

/* Not the official Apple and Google artwork. The App Store badge is a real
   link and the primary call to action; the Play badge is still a span,
   because a badge that looks like a button but does nothing is worse than a
   line of text. It becomes a link the day Play goes live. */

.stores {
    display: flex;
    gap: 18px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 38px;
}

.store-badge {
    display: inline-flex;
    align-items: center;
    gap: 18px;
    padding: 19px 34px;
    /* Both badges match whichever name is longer, so they read as a pair
       rather than as two differently sized things. */
    min-width: 304px;
    border-radius: 14px;
    background: var(--elevated);
    border: 1px solid var(--border-hover);
    /* A single hairline of light along the top edge, which is what keeps a
       flat dark rectangle from looking like a hole in the page. */
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* The App Store badge is a real destination now and the Play one is not, so
   the pair can no longer look identical: the live one takes a hover, a lift
   and a focus ring, and the pending one is held back a step. */
a.store-badge {
    text-decoration: none;
    transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

a.store-badge:hover,
a.store-badge:focus-visible {
    transform: translateY(-2px);
    border-color: var(--purple);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08),
                0 10px 26px rgba(0, 0, 0, 0.45);
}

a.store-badge:focus-visible {
    outline: 2px solid var(--purple-light);
    outline-offset: 3px;
}

.store-badge--pending { opacity: 0.6; }

/* Lifted from .btn-primary rather than reinvented: the download is now the
   strongest action on the page, and two different purples would read as two
   different kinds of button. */
a.store-badge--primary {
    background: rgba(139, 92, 246, 0.20);
    border: 1px solid transparent;
    background-image:
        linear-gradient(rgba(139, 92, 246, 0.20), rgba(139, 92, 246, 0.20)),
        linear-gradient(to bottom, rgba(233, 213, 255, 0.95), rgba(192, 132, 252, 0.8) 25%, rgba(139, 92, 246, 0.45));
    background-origin: border-box;
    background-clip: padding-box, border-box;
    /* Two wide halos read as a light fitting rather than a button. The
       purple edge does the brand work; a real shadow does the lifting. */
    box-shadow: 0 0 14px rgba(168, 85, 247, 0.22), 0 6px 20px rgba(0, 0, 0, 0.45);
}

/* The gradient lives in the border box, so a literal border-color would
   paint over it. This variant overrides the plain link hover above. */
a.store-badge--primary:hover,
a.store-badge--primary:focus-visible {
    border-color: transparent;
    box-shadow: 0 0 20px rgba(168, 85, 247, 0.38), 0 10px 26px rgba(0, 0, 0, 0.5);
    filter: brightness(1.08) saturate(1.15);
}

/* The glass fill is light where this text sits, so the light-on-purple that
   .btn-primary uses measures about 2.6:1 here. Dark text on the same fill is
   7:1 for the label and 5.3:1 for the name. The Apple glyph follows the text
   colour rather than staying white for the same reason. */
a.store-badge--primary { color: #2d0a56; }
a.store-badge--primary .store-text small { color: rgba(45, 10, 86, 0.86); }
a.store-badge--primary .store-text strong { color: #2d0a56; }

@media (prefers-reduced-motion: reduce) {
    a.store-badge { transition: none; }
    a.store-badge:hover,
    a.store-badge:focus-visible { transform: none; }
}

.store-glyph { width: 38px; height: 40px; flex: none; }

.store-text {
    display: flex;
    flex-direction: column;
    /* Centred text under a left-aligned glyph reads as a mistake, and the
       two lines have to share one left edge to look like one label. */
    text-align: left;
    line-height: 1.16;
}

.store-text small {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.10em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.store-text strong {
    font-size: 25px;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--text);
}

@media (max-width: 640px) {
    /* Two 252px badges do not fit side by side, and letting them wrap leaves
       one stranded and centred under the other. Stacked full width instead. */
    .stores { gap: 12px; }
    .store-badge { width: 100%; min-width: 0; justify-content: center; }
}

/* --------------------------------------------------------------- section */

section { padding: 72px 0; }
.section-head { max-width: 660px; margin-bottom: 42px; }

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

.card {
    background: linear-gradient(145deg, #111111, #0d0d0d);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 26px;
    transition: border-color 0.2s ease, transform 0.2s ease;
}
.card:hover { border-color: var(--border-hover); transform: translateY(-2px); }
.card p { margin: 0; font-size: 15px; }

.card .ico {
    width: 42px;
    height: 42px;
    border-radius: 11px;
    display: grid;
    place-items: center;
    font-size: 20px;
    margin-bottom: 16px;
    background: rgba(139, 92, 246, 0.14);
    border: 1px solid rgba(139, 92, 246, 0.3);
}

.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 18px;
    text-align: center;
}
.stat { padding: 26px 16px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); }
.stat b { display: block; font-size: 34px; font-weight: 800; letter-spacing: -0.02em; }
.stat span { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-muted); }

/* ----------------------------------------------------------- screenshots */

.shots {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 260px;
    gap: 20px;
    overflow-x: auto;
    padding: 6px 4px 22px;
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
}
.shot { scroll-snap-align: center; }
.shot img {
    width: 100%;
    /* The width/height attributes on the img are there so the browser reserves
       the right space before the file loads. Without height:auto they would
       also be honoured literally, pinning every shot to 1390px tall. */
    height: auto;
    display: block;
    border-radius: 26px;
    border: 1px solid var(--border-hover);
    background: var(--card);
}
.shot figcaption { font-size: 13px; color: var(--text-muted); text-align: center; margin-top: 12px; }

/* The button exists so a screenshot can be opened from the keyboard and read
   as interactive; it is deliberately invisible and inherits the image's own
   frame rather than drawing a second one around it. */
.shot-open {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: zoom-in;
    border-radius: 26px;
    -webkit-tap-highlight-color: transparent;
}
.shot-open img { transition: transform 160ms ease, box-shadow 160ms ease; }
.shot-open:hover img,
.shot-open:focus-visible img {
    /* A hint that something will happen, not the enlargement itself: .shots
       scrolls horizontally, so anything scaled up in place is cut off at the
       container edge. The real preview is a fixed overlay. */
    transform: translateY(-4px);
    box-shadow: 0 18px 50px rgba(139, 92, 246, 0.35);
}
.shot-open:focus-visible { outline: 2px solid var(--purple-light); outline-offset: 6px; }

/* ------------------------------------------------------------------ form */

/* The site has never had a form before /reset, so these exist only for it.
   Kept in the shared sheet rather than inlined because a password field
   styled by hand on one page is a password field that stops matching the
   rest of the site the first time a token changes. */

.field-label {
    display: block;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
}

input[type="password"],
input[type="email"],
input[type="text"] {
    width: 100%;
    padding: 14px 16px;
    font-size: 16px;
    /* 16px exactly: anything smaller and iOS Safari zooms the page on focus,
       which on a phone looks like the layout breaking. */
    font-family: inherit;
    color: var(--text);
    background: var(--elevated);
    border: 1px solid var(--border-hover);
    border-radius: 12px;
    box-sizing: border-box;
}
input::placeholder { color: var(--text-subtle); }
input:focus {
    outline: none;
    border-color: var(--purple);
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.25);
}

/* .btn was written for anchors, and a <button> brings its own font, border
   and cursor that would otherwise leak through. */
button.btn {
    font-family: inherit;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}
button.btn[disabled] { opacity: 0.6; cursor: default; }

/* -------------------------------------------------------------- lightbox */

#shotbox {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: grid;
    place-items: center;
    padding: 32px;
    background: rgba(6, 5, 10, 0.86);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 160ms ease, visibility 160ms;
}
#shotbox[data-open] { opacity: 1; visibility: visible; }

#shotbox img {
    max-height: calc(100vh - 64px);
    max-width: min(92vw, 420px);
    width: auto;
    height: auto;
    border-radius: 30px;
    border: 1px solid var(--border-hover);
    box-shadow: 0 30px 90px rgba(0, 0, 0, 0.7), 0 0 70px rgba(139, 92, 246, 0.28);
    transform: scale(0.97);
    transition: transform 160ms ease;
}
#shotbox[data-open] img { transform: scale(1); }

/* Only shown for a click, which is the one case the viewer has to dismiss
   themselves. A hover preview goes away on its own. */
#shotbox button {
    position: absolute;
    top: 18px;
    right: 18px;
    width: 44px;
    height: 44px;
    border-radius: 999px;
    border: 1px solid var(--border-hover);
    background: var(--elevated);
    color: var(--text);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}
#shotbox:not([data-sticky]) button { display: none; }

@media (prefers-reduced-motion: reduce) {
    .shot-open img, #shotbox, #shotbox img { transition: none; }
    .shot-open:hover img, .shot-open:focus-visible img { transform: none; }
}

/* Stands in until real screenshots are dropped into public/shots/. */
.shot .placeholder {
    aspect-ratio: 9 / 19.5;
    border-radius: 26px;
    border: 1px dashed var(--border-hover);
    background: linear-gradient(160deg, rgba(139, 92, 246, 0.09), rgba(10, 10, 10, 0.4));
    display: grid;
    place-items: center;
    color: var(--text-subtle);
    font-size: 13px;
    text-align: center;
    padding: 20px;
}

/* --------------------------------------------------------------- privacy */

.privacy-points { list-style: none; padding: 0; margin: 0; display: grid; gap: 12px; }
.privacy-points li {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 16px 18px;
    color: var(--text-body);
    font-size: 15px;
}
.privacy-points .tick { color: var(--success); font-weight: 700; }

/* ------------------------------------------------------------------- faq */

details {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 18px 20px;
    margin-bottom: 12px;
}
details[open] { border-color: var(--border-hover); }
summary {
    cursor: pointer;
    font-weight: 600;
    list-style: none;
    display: flex;
    justify-content: space-between;
    gap: 16px;
}
summary::-webkit-details-marker { display: none; }
summary::after { content: "+"; color: var(--purple-light); font-weight: 700; }
details[open] summary::after { content: "\2212"; }
details p { margin: 14px 0 0; font-size: 15px; }

/* ------------------------------------------------------------------- doc */

.doc { padding: 56px 0 80px; }
.doc h2 { margin-top: 44px; font-size: 24px; }
.doc h3 { margin-top: 28px; }
.doc ul { color: var(--text-body); padding-left: 22px; }
.doc li { margin-bottom: 9px; }
.doc .updated { font-size: 14px; color: var(--text-subtle); }
.doc table { width: 100%; border-collapse: collapse; margin: 18px 0; font-size: 15px; }
.doc th, .doc td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--border); vertical-align: top; }
.doc th { color: var(--text); font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; }
.doc td { color: var(--text-body); }

.callout {
    background: rgba(139, 92, 246, 0.08);
    border: 1px solid rgba(139, 92, 246, 0.3);
    border-radius: 12px;
    padding: 18px 20px;
    margin: 24px 0;
}
.callout p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- footer */

footer {
    border-top: 1px solid var(--border);
    padding: 40px 0;
    margin-top: 40px;
}
.foot {
    display: flex;
    gap: 24px;
    align-items: center;
    flex-wrap: wrap;
    font-size: 14px;
    color: var(--text-subtle);
}
.foot nav { display: flex; gap: 24px; margin-left: auto; }
.foot a { color: var(--text-muted); }

@media (max-width: 640px) {
    .nav { gap: 18px; }
    .nav a.link { font-size: 14px; }
    section { padding: 52px 0; }
    /* The 24px matters: .hero's shorthand lands after .wrap and would
       otherwise zero the gutter every other section keeps, putting the
       headline, the lede and the store badges hard against both edges of
       the phone. */
    .hero { padding: 60px 24px 46px; }
    .foot nav { margin-left: 0; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    * { transition: none !important; }
}

/* ------------------------------------------------------------- breeder pages */
/* Wide catalogs scroll inside their own box rather than pushing the page
   sideways on a phone, which is where most of this traffic lands. */
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 14px; }
table.strains { width: 100%; border-collapse: collapse; font-size: 14px; min-width: 520px; }
table.strains th {
    text-align: left;
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-subtle);
    padding: 12px 14px;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
table.strains td { padding: 11px 14px; border-bottom: 1px solid rgba(255,255,255,0.06); color: var(--text-body); }
table.strains tr:last-child td { border-bottom: 0; }
table.strains td:first-child { color: var(--text); font-weight: 600; }
table.strains tbody tr:hover td { background: rgba(139, 92, 246, 0.05); }

.breeder-index { list-style: none; padding: 0; margin: 0; column-width: 240px; column-gap: 26px; }
.breeder-index li {
    break-inside: avoid;
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 0;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.breeder-index a { color: var(--text); text-decoration: none; }
.breeder-index a:hover { color: var(--purple-light); }
.breeder-index span { color: var(--text-subtle); font-size: 13px; font-variant-numeric: tabular-nums; }

/* Reported effects, flavours and aromas: short labels that wrap. */
.chip-group { margin-bottom: 22px; }
.chip-group h3 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-subtle); margin-bottom: 10px; }
.chips { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.chips li {
    font-size: 13px;
    color: var(--text-body);
    background: rgba(139, 92, 246, 0.10);
    border: 1px solid rgba(139, 92, 246, 0.28);
    border-radius: 999px;
    padding: 5px 13px;
}

/* Generated pages put their subject in an h1, but these are reference pages,
   not a hero: the h1 default of up to 68px belongs on the landing page only. */
.page-title { font-size: clamp(28px, 4vw, 38px); line-height: 1.15; letter-spacing: -0.015em; margin: 0 0 16px; }
.crumbs { font-size: 13px; color: var(--text-subtle); margin-bottom: 18px; }
.crumbs a { color: var(--text-muted); }
.crumbs a:hover { color: var(--purple-light); }

/* ----------------------------------------------------------- strain search */

.search-box {
    width: 100%;
    padding: 15px 18px;
    margin-bottom: 14px;
    font: inherit;
    font-size: 17px;
    color: var(--text);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 12px;
    -webkit-appearance: none;
    appearance: none;
}
.search-box::placeholder { color: var(--text-subtle); }
.search-box:focus {
    outline: none;
    border-color: rgba(139, 92, 246, 0.55);
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.18);
}

.filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }

.chip-btn {
    padding: 8px 15px;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-body);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.chip-btn:hover { border-color: var(--border-hover); color: var(--text); }
/* The selected filter, matching the app's chip row. */
.chip-btn.on {
    color: var(--glow);
    background: rgba(139, 92, 246, 0.2);
    border-color: rgba(139, 92, 246, 0.65);
}

/* Search results and the related-strain list. Two lines rather than the
   breeder index's single row: a strain needs its breeder beside it (the same
   name is sold by a dozen of them) and that does not fit on one line beside
   flowering time and potency. */
.breeder-list { list-style: none; padding: 0; margin: 0; }
.breeder-list li {
    padding: 11px 0;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.breeder-list a {
    display: block;
    color: var(--text);
    text-decoration: none;
    font-weight: 600;
}
.breeder-list a:hover { color: var(--purple-light); }
.breeder-list span {
    display: block;
    margin-top: 3px;
    font-size: 13px;
    color: var(--text-subtle);
}


/* ---------------------------------------------------------------------------
   The season ribbon.

   A calendar band from March to November with the frost dates as hard walls,
   and a plant's life drawn between them. A segment that runs past the first
   frost is striped in alert red, which is the whole point: you see a
   photoperiod fail in northern Minnesota rather than reading a number.

   Used by both planning tools, and built by the same markup in Python for the
   region pages and in JavaScript for the planner, so the two cannot drift.
   --------------------------------------------------------------------------- */
.ribbon { position: relative; margin: 18px 0 10px; }
/* Each label sits at its real date, because the window is now per region:
   the months in it are not the same length, it does not begin on the first of
   one, and a southern season runs into the next year. */
.ribbon .months {
    position: relative; height: 13px; margin-bottom: 6px;
    font-size: 10px; letter-spacing: 0.16em; color: var(--text-subtle);
    text-transform: uppercase;
}
.ribbon .months span { position: absolute; top: 0; padding-left: 2px; }
.ribbon .plot {
    position: relative; border: 1px solid var(--border);
    border-radius: 10px; background: var(--elevated); overflow: hidden;
    /* Vertical only. The percentage positions below are relative to this
       box, so any horizontal padding would shift every frost date. */
    padding: 10px 0 14px;
}
.ribbon .frostzone {
    position: absolute; top: 0; bottom: 0;
    background: repeating-linear-gradient(-45deg,
        rgba(96,165,250,0.16) 0 5px, transparent 5px 10px);
}
.ribbon .frostwall {
    position: absolute; top: 0; bottom: 0; width: 2px;
    background: var(--cyan); opacity: 0.8;
}
.ribbon .track {
    position: relative; height: 34px; margin: 9px 0;
}
.ribbon .seg {
    position: absolute; top: 0; height: 100%; border-radius: 4px;
    font-size: 11px; font-weight: 600; color: #0a0a0a;
    display: flex; align-items: center; padding: 0 7px;
    white-space: nowrap; overflow: hidden;
}
.ribbon .seg-germ   { background: #5c6b62; color: var(--text); }
.ribbon .seg-veg    { background: var(--success); }
.ribbon .seg-flower { background: var(--sun); }
/* Striped, not just red: it has to read as wrong at a glance and still read
   as wrong to someone who cannot separate red from green. */
.ribbon .seg-over {
    background: repeating-linear-gradient(-45deg,
        var(--alert) 0 6px, #7f1d1d 6px 12px);
    color: var(--text);
}
.ribbon .tracklabel {
    font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--text-muted); margin: 12px 0 0 2px;
}
.ribbon .frostlabels {
    display: flex; justify-content: space-between;
    font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--cyan); margin-top: 6px;
}
.legend {
    display: flex; flex-wrap: wrap; gap: 14px;
    font-size: 12px; color: var(--text-muted); margin-top: 12px;
}
.legend i {
    display: inline-block; width: 11px; height: 11px;
    border-radius: 3px; margin-right: 6px; vertical-align: -1px;
}
.verdict {
    display: inline-block; font-size: 11px; font-weight: 700;
    letter-spacing: 0.14em; text-transform: uppercase;
    padding: 5px 10px; border-radius: 999px; border: 1px solid;
}
.v-ok    { color: var(--success); border-color: rgba(34,197,94,0.4);  background: rgba(34,197,94,0.08); }
.v-tight { color: var(--sun);     border-color: rgba(240,165,0,0.4);  background: rgba(240,165,0,0.08); }
.v-late  { color: var(--alert);   border-color: rgba(239,68,68,0.4);  background: rgba(239,68,68,0.08); }

.tool-controls {
    display: flex; flex-wrap: wrap; gap: 16px; margin: 20px 0 4px;
}
.tool-controls .field { display: flex; flex-direction: column; gap: 7px; min-width: 190px; flex: 1 1 190px; }
.tool-controls label {
    font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--text-muted);
}
.tool-controls select,
.tool-controls input[type="date"],
.tool-controls input[type="search"] {
    width: 100%; padding: 11px 12px; font: inherit; font-size: 15px;
    color: var(--text); background: var(--card);
    border: 1px solid var(--border); border-radius: 10px;
}
.tool-controls select:focus,
.tool-controls input:focus {
    outline: 2px solid var(--purple); outline-offset: 1px; border-color: var(--purple);
}
.tool-controls input[type="range"] { width: 100%; accent-color: var(--purple); }

.tag {
    display: inline-block; font-size: 10px; font-weight: 700;
    letter-spacing: 0.1em; padding: 2px 6px; border-radius: 5px;
    background: var(--border); color: var(--text-muted);
}
.tag-auto { background: rgba(139,92,246,0.16); color: var(--purple-light); }
.tag-mold { background: rgba(34,197,94,0.14); color: var(--success); }

@media (prefers-reduced-motion: reduce) {
    .card:hover { transform: none; }
}


/* Related-variety groups. The heading carries the claim, so it has to read as
   a label rather than as another line of body text. */
.rel-kind {
    font-size: 12px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--purple-light);
    margin: 0 0 4px;
}


/* The station a region's frost dates came from, under its name. Quiet, but
   present: a grower is entitled to know the number is an airport and not
   their garden. */
.cite {
    display: block; margin-top: 2px;
    font-size: 11px; font-weight: 400; color: var(--text-subtle);
}


/* A card heading is a section heading, whatever its level. The two on /tools
   are the page's only sections, so they are h2 and the document went h1 to h3
   without them; they are sized like the h3 they replaced so only the outline
   changed. */
.card h2 { font-size: 19px; font-weight: 700; margin: 0 0 8px; }


/* A link in a sentence has to be findable without colour. */
p a, .crumbs a, .legend a {
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-thickness: 1px;
}
p a:hover, .crumbs a:hover { text-decoration-thickness: 2px; }


/* The first light frost, which a mature plant walks through. Dashed and dimmer
   than the killing freeze beside it, because it marks a risk rather than an
   end. */
.ribbon .frostwall.soft {
    width: 0; border-left: 2px dashed var(--cyan); opacity: 0.45;
}


/* ------------------------------------------------------------- adverts */

/* The slot sits between the content and the footer, so a banner that arrives
   after the page has painted pushes nothing but the footer down. Anywhere
   higher would move the record the reader came for, and these are the pages
   that rank. */
.ad-slot { padding: 8px 0 40px; }
.ad-slot[hidden] { display: none; }

.ad-unit {
    max-width: var(--max);
    margin: 0 auto;
    padding: 0 24px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

/* Said plainly rather than hidden in 9px grey. A reader who cannot tell an
   advert from the catalogue is the one thing this site cannot afford. */
.ad-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.ad-shell {
    max-width: 100%;
    line-height: 0;
    border-radius: 8px;
    overflow: hidden;
}

.ad-disclosure {
    margin: 0;
    font-size: 12px;
    color: var(--text-subtle);
    text-align: center;
}


/* ================================================================ home v2

   The app is far more restrained than this site used to be. Its screens are
   near-black, purple appears on labels and the selected day and almost nowhere
   else, and colour is carried by the stage pills. These rules bring the page
   in line with that: one accent, real screenshots, and layouts that differ
   from one another so the eye has somewhere to go.
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------- hero v2 */

/* Two columns on desktop, stacked on a phone. The screenshot is the point of
   the hero, so it is a real capture at a real size rather than artwork. */
.hero2 {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    gap: 56px;
    align-items: center;
    /* Vertical only. The shorthand here would override .wrap's 0 24px on the
       same element and put the headline hard against the viewport edge. */
    padding-top: 64px;
    padding-bottom: 56px;
}
.hero2 h1 {
    font-size: clamp(38px, 5.2vw, 60px);
    line-height: 1.04;
    letter-spacing: -0.03em;
    margin: 0 0 20px;
}
/* One solid accent, not a gradient. The phrase is the brand; the rainbow was
   decoration that fought the screenshot beside it. */
.hero2 h1 em { font-style: normal; color: var(--purple-light); }
.hero2 .lede { font-size: 19px; margin-bottom: 28px; }

.hero-cta { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.hero-cta .store-badge { margin: 0; }

/* Android is real but not shipped, so it is a sentence rather than a second
   badge competing with the one button that works. */
.hero-later {
    font-size: 13px;
    color: var(--text-subtle);
    margin: 14px 0 0;
}
.hero-later b { color: var(--text-muted); font-weight: 600; }

/* The three things a visitor most needs to believe, directly under the CTA. */
.facts {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 10px 22px;
    padding: 0;
    margin: 26px 0 0;
}
.facts li {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    color: var(--text-body);
}
.facts svg { width: 15px; height: 15px; color: var(--success); flex: none; }

/* ------------------------------------------------------------ the device */

/* A thin bezel, because the capture already has the app's own rounded corners
   and status bar. Anything heavier turns a product shot into a stock photo. */
.device {
    display: block;
    position: relative;
    border-radius: 30px;
    padding: 7px;
    background: linear-gradient(160deg, #2a2740, #141420);
    border: 1px solid var(--border-hover);
    box-shadow: 0 30px 70px rgba(0, 0, 0, 0.55);
    max-width: 340px;
    margin: 0 auto;
}
.device img { display: block; width: 100%; height: auto; border-radius: 24px; }
.device--sm { max-width: 270px; }

/* ------------------------------------------------------- workflow blocks */

/* Alternating, so three consecutive sections do not read as one grid. */
.flow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 360px);
    gap: 60px;
    align-items: center;
    padding: 56px 0;
    border-top: 1px solid var(--border);
}
.flow:nth-child(even) > .flow-shot { order: -1; }
.flow h3 { font-size: 27px; letter-spacing: -0.02em; margin: 10px 0 14px; }
.flow p { font-size: 16px; }
.flow-detail {
    list-style: none;
    padding: 0;
    margin: 18px 0 0;
    display: grid;
    gap: 9px;
}
.flow-detail li {
    font-size: 14px;
    color: var(--text-muted);
    padding-left: 18px;
    position: relative;
}
.flow-detail li::before {
    content: "";
    position: absolute;
    left: 0; top: 9px;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--purple);
}

/* ----------------------------------------------------- secondary features */

/* A list, not nine cards. These are the things worth knowing once you are
   already interested, and they do not each deserve a panel. */
.featlist {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
    gap: 28px 40px;
}
.featlist li { display: flex; gap: 14px; align-items: flex-start; }
.featlist .fi {
    flex: none;
    width: 34px; height: 34px;
    display: grid; place-items: center;
    border-radius: 9px;
    background: rgba(139, 92, 246, 0.12);
    border: 1px solid rgba(139, 92, 246, 0.28);
    color: var(--purple-light);
}
.featlist .fi svg { width: 17px; height: 17px; }
.featlist h4 { margin: 2px 0 5px; font-size: 15px; font-weight: 650; }
.featlist p { margin: 0; font-size: 14px; color: var(--text-muted); }

/* ------------------------------------------------------------- the plans */

.plans {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
    align-items: start;
}
.plan {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 26px;
}
.plan--pro { border-color: rgba(139, 92, 246, 0.45); }

/* Free is the word that gets people to try it, and as a grey 11px label above
   a grey $0 it was the quietest thing in the section. It gets the same
   treatment Pro already had, an edged card and a coloured label, in the green
   the checkmarks throughout the page use, and the label is set large enough to
   be read as a statement rather than a category heading. */
.plan--free { border-color: rgba(34, 197, 94, 0.38); }

.plan .tier {
    font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
    color: var(--text-muted); font-weight: 700;
    /* Pinned so the larger free label does not push its own price 5px below
       the one it sits beside. The cards are read across, not down. */
    line-height: 18px;
}
.plan--pro .tier { color: var(--purple-light); }
.plan--free .tier { color: var(--success); font-size: 14px; letter-spacing: 0.14em; }
.plan .price { font-size: 32px; font-weight: 800; letter-spacing: -0.02em; margin: 10px 0 2px; }
.plan--free .price { color: var(--success); }
.plan .price small { font-size: 14px; font-weight: 500; color: var(--text-muted); letter-spacing: 0; }
.plan .per { font-size: 13px; color: var(--text-subtle); margin: 0 0 18px; }
.plan ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
.plan li { font-size: 14px; color: var(--text-body); padding-left: 22px; position: relative; }
.plan li::before {
    content: "";
    position: absolute; left: 0; top: 7px;
    width: 10px; height: 6px;
    border-left: 2px solid var(--success);
    border-bottom: 2px solid var(--success);
    transform: rotate(-45deg);
}
.plan li.no { color: var(--text-subtle); }
.plan li.no::before {
    border: 0; top: 9px; left: 2px;
    width: 8px; height: 2px; background: var(--text-subtle); transform: none;
}

/* --------------------------------------------------------- the maker note */

.maker {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 26px;
}
.maker img { width: 56px; height: 56px; border-radius: 12px; }
.maker p { margin: 0 0 12px; font-size: 15px; }
.maker p:last-child { margin-bottom: 0; }

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

@media (max-width: 900px) {
    .hero2, .flow { grid-template-columns: 1fr; gap: 36px; }
    .hero2 { padding-top: 40px; padding-bottom: 44px; text-align: left; }
    /* The screenshot leads on a phone: it says what the app is faster than the
       paragraph does, and it is the reason anyone scrolls on. */
    .hero2 > .hero-shot { order: -1; }
    .flow:nth-child(even) > .flow-shot { order: 0; }
    .device { max-width: 300px; }
    .maker { grid-template-columns: 1fr; }
}


/* ============================================================== polish pass

   Section rhythm, a header download link, and the closing block.
   ------------------------------------------------------------------------ */

/* `section { padding: 72px 0 }` has never applied to anything on this site.
   Every section also carries .wrap, and a class beats an element selector no
   matter which is written first, so .wrap's `padding: 0 24px` won and the
   vertical padding was silently dropped. What spacing existed came from
   whatever margins the contents happened to have, which is why the gaps
   between sections measured 64, 45, 20, 20 and once -32 instead of one value.

   section.wrap outranks .wrap, and padding-block leaves the 24px gutter
   alone. */
main > section.wrap { padding-block: 88px; }
main > section.wrap:first-of-type { padding-block-start: 72px; }

/* The label belongs to the heading under it, not to the section above, so the
   pair stays tight while the sections themselves breathe. */
.section-head { margin-bottom: 40px; }
.section-head .eyebrow { margin-bottom: 10px; }
.section-head p { margin-bottom: 0; }

/* The workflow rows already separate themselves with a rule and their own
   padding; the section around them should not add a third gap on top. */
#features { padding-block-end: 56px; }
#features .flow:first-of-type { border-top: 0; padding-top: 0; }

/* ------------------------------------------------------- header get the app */

/* A download link in the nav, styled as a link rather than a button so it does
   not compete with the badge in the hero. It is the first thing dropped when
   the bar gets tight, because the hero button is two seconds away. */
.nav a.link.nav-get {
    color: var(--purple-light);
    font-weight: 600;
}
.nav a.link.nav-get:hover { color: var(--glow); }

@media (max-width: 860px) {
    .nav a.link.nav-get { display: none; }
}

/* --------------------------------------------------------------- closing */

.closing {
    text-align: center;
    border-top: 1px solid var(--border);
}
.closing h2 { margin-bottom: 12px; }
.closing p { max-width: 520px; margin-left: auto; margin-right: auto; }
.closing .actions { margin-top: 26px; }
.closing .note { margin-top: 18px; }

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

@media (max-width: 900px) {
    main > section.wrap { padding-block: 60px; }
    main > section.wrap:first-of-type { padding-block-start: 48px; }
    .section-head { margin-bottom: 30px; }
    #features { padding-block-end: 36px; }
}

/* "start to cure." is the phrase, and breaking it left "cure." alone on a line
   at several desktop widths. Holding it together with non-breaking spaces in
   the markup fixed that and broke small phones instead: as one unbreakable
   run it overflowed at 375 and 320. Doing it in CSS keeps it whole wherever
   there is room and lets it wrap naturally where there is not. */
@media (min-width: 560px) {
    .hero2 h1 em { white-space: nowrap; }
}
