/* ==========================================================================
   Piren — forms.

   PAGE-SCOPED, unlike the other four sheets. tokens / base / components /
   sections / layout are linked by every page because every page uses them;
   this one is ~6 kB serving a single form on a single page, so it is linked
   only by the page that has the form. Add the <link> to any other page that
   grows one.

   It is still an ordinary repo stylesheet, NOT a co-located
   components/<name>/<name>.css — the deploy scopes those with a
   [data-wl-c="…"] prefix that can never match a component root, and they were
   all deleted for that reason. See the header of components.css.

   Because this is a normal stylesheet, the component root CAN live here: no
   [data-wl-component="…"] duplicate in layout.css is needed, since no
   breakpoint tier reaches into this form.
   ========================================================================== */

.abonnering-form{
  container-type:inline-size;
  container-name:abform;
  /* One column until the form itself has room for two. Fields are short and
     paired (name/email, start/end), so two columns read as pairs rather than
     as a wall — but only once each column still holds a real input. */
  --ab-cols:1fr;
}
/* THE TARGET MUST BE A DESCENDANT. This rule used to set --ab-cols on
   .abonnering-form itself — the very element that declares the container — and
   a container query can never style its own container. So --ab-cols stayed 1fr
   at every width and this form has never rendered two columns. Setting it on
   .ab-form__inner (inside the container) lets it inherit down to .ab-grid and
   .ab-minimum__list as intended. */
@container abform (min-width: 30rem){
  .ab-form__inner{--ab-cols:repeat(2, 1fr)}
}

.ab-form__inner{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:var(--space-snug);
}
.ab-form__intro{
  display:flex;
  flex-direction:column;
  align-items:center;
  text-align:center;
  gap:var(--space-hair);
  margin-inline:auto;
  max-inline-size:var(--measure-wide);
}
.ab-form__heading{
  font-size:var(--type-h1);
  line-height:var(--line-height-tight);
  color:var(--text-heading);
}
.ab-form__lead{
  max-inline-size:var(--measure-prose);
  font-size:var(--type-lead);
  line-height:var(--line-height-normal);
  font-weight:var(--font-body-medium);
}
/* The second line is smaller and quieter on the live form. */
.ab-form__lead--minor{
  font-size:var(--type-body);
  font-weight:var(--font-body-regular);
  color:var(--text-muted);
}

.ab-form{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:var(--space-snug);
  /* NOT --measure-wide. That is 64ch, almost exactly the two-column
     breakpoint below, so the form sat on the boundary and collapsed to one
     column at every realistic width — which is the single biggest reason it
     did not look like the original. Fields are short and paired; the prose
     above them keeps its own narrower measure. */
}

/* --- Sections --------------------------------------------------------------
   A real <fieldset>/<legend>: the legend names the group for a screen reader
   the same way the heading does on sight, which a styled <div> + <h2> cannot
   do. Both browser defaults are reset because the native border and legend
   placement fight the rest of the page. */
.ab-fieldset{
  border:0;
  padding:0;
  margin:0;
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:var(--space-tight);
  padding-block-start:var(--space-tight);
  border-block-start:var(--border-width-main) solid var(--border-color-hairline);
}
.ab-fieldset:first-of-type{border-block-start:0;padding-block-start:0}
.ab-fieldset__legend{
  padding:0;
  font-family:var(--font-display);
  font-weight:var(--font-display-bold);
  font-size:var(--type-h3);
  line-height:var(--line-height-tight);
  color:var(--text-heading);
}
.ab-fieldset__note{
  max-inline-size:var(--measure-prose);
  font-size:var(--type-sm);
  line-height:var(--line-height-relaxed);
  color:var(--text-muted);
}

.ab-subhead{
  font-family:var(--font-display);
  font-weight:var(--font-display-bold);
  font-size:var(--type-h4);
  line-height:var(--line-height-tight);
  color:var(--text-heading);
}
.ab-subhead--minor{
  font-family:var(--font-body);
  font-weight:var(--font-body-medium);
  font-size:var(--type-md);
  margin-block-start:var(--space-hair);
}

.ab-block{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:var(--space-hair);
}

/* --- Fields ----------------------------------------------------------------
   Inputs inherit the page's own type rather than the browser's: at 16px the
   body face keeps iOS from zooming the viewport on focus, which is the usual
   cause of a form that jumps about on a phone. */
.ab-grid{
  display:grid;
  grid-template-columns:var(--ab-cols);
  gap:var(--space-tight);
  align-items:start;
}
.ab-field--full{grid-column:1 / -1}
.ab-field{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:.3rem;
}
/* NOT bold, and not small. On the live form the field labels are plain
   .ab_frm_label — only .ab_frm_label.u-text-small carries font-weight:700, and
   the field labels do not have that class. Ours were bold at --type-sm, which
   is what made them read as heavier and tighter than the original. */
.ab-label{
  font-weight:var(--font-body-regular);
  font-size:var(--type-body);
  color:var(--text-heading);
}

/* The capacity note under the guest count. Carries real information — it is
   the map's rule in words — so it is not styled as a faint hint. */
.ab-note{
  max-inline-size:var(--measure-prose);
  font-size:var(--type-sm);
  line-height:var(--line-height-relaxed);
}
/* Matched to piren-bar.se: fields are FILLED WHITE against the cream page, not
   transparent. On the live site that white comes from Webflow's own .w-input
   base rule, which is easy to miss when reading their form CSS — .ab_frm_field
   only sets border and padding and inherits the fill. Ours has to state it. */
.ab-input{
  inline-size:100%;
  /* .5rem .75rem — Webflow's own 8px/12px, which is what the live fields
     ACTUALLY use. Their .ab_frm_field asks for 1.5rem of vertical padding, but
     .w-input pins height to 38px and box-sizing clips it away, so reading their
     padding declaration and copying it makes the field roughly twice as tall as
     the thing it is copying. */
  padding:.5rem .75rem;
  /* #c9cfc5 — the live form's --_theme---theme--brand. Ours defaulted to the
     dark border token, which is why the fields read as outlined boxes rather
     than the soft-edged ones on piren-bar.se. */
  border:var(--border-width-main) solid var(--color-primary-200);
  background:#fff;
  color:var(--color-secondary-900);
  font-family:var(--font-body);
  font-size:var(--type-body);
  line-height:var(--line-height-normal);
}
.ab-input:focus{border-color:var(--color-secondary-800)}

/* The two time fields. A select needs its own arrow once appearance is reset,
   or it reads as a text input that mysteriously will not accept typing. */
.ab-select{
  appearance:none;
  padding-inline-end:2.25rem;
  background-image:linear-gradient(45deg,transparent 50%,var(--color-secondary-800) 50%),
                   linear-gradient(135deg,var(--color-secondary-800) 50%,transparent 50%);
  background-position:calc(100% - 1.1rem) 55%, calc(100% - .75rem) 55%;
  background-size:.35rem .35rem,.35rem .35rem;
  background-repeat:no-repeat;
  cursor:pointer;
}
.ab-input::placeholder{color:var(--text-muted);opacity:1}
.ab-textarea{resize:vertical;min-block-size:6rem;padding:var(--space-hair)}
.ab-input--qty{inline-size:5rem;flex:none}

.ab-hint{
  max-inline-size:var(--measure-prose);
  font-size:var(--type-xs);
  line-height:var(--line-height-relaxed);
  color:var(--text-muted);
}

/* --- Choices ---------------------------------------------------------------
   The whole row is the label, so the hit area is the line and not the 16px
   control — the difference between a comfortable and a fiddly form on a
   phone. */
.ab-options{
  display:flex;
  flex-direction:column;
  align-items:stretch;
}
.ab-option{
  border-block-end:var(--border-width-main) solid var(--border-color-hairline);
}
.ab-option:last-child{border-block-end:0}
.ab-option__row{
  display:flex;
  align-items:flex-start;
  gap:.9ch;
  padding-block:.7rem;
  cursor:pointer;
}
.ab-option--qty{
  display:flex;
  flex-flow:row wrap;
  justify-content:space-between;
  align-items:center;
  gap:var(--space-hair);
  padding-block:.7rem;
}
.ab-option__body{
  flex:1;
  min-inline-size:0;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:.1rem;
}
.ab-option__name{
  font-size:var(--type-body);
  line-height:var(--line-height-normal);
  color:var(--text-heading);
}
.ab-option__meta{
  font-size:var(--type-sm);
  line-height:var(--line-height-relaxed);
  color:var(--text-muted);
}
.ab-option__qty{display:flex;align-items:center;gap:var(--space-hair)}

/* 1.5rem, matching .radio_circle_wrap on piren-bar.se — the live controls are
   noticeably bigger than a browser default, and at this size the whole row
   reads as tappable rather than the control being a target to hunt for.
   
   Built on the NATIVE input with appearance:none and a ::after dot, rather than
   a hidden input beside a decorative span as the original does. Same result,
   same easing, but focus, keyboard and screen-reader behaviour stay the
   browser's — nothing to reimplement and nothing to get wrong. */
.ab-radio,
.ab-checkbox{
  appearance:none;
  -webkit-appearance:none;
  inline-size:1.5rem;
  block-size:1.5rem;
  flex:none;
  margin:.05em 0 0;
  display:grid;
  place-items:center;
  border:var(--border-width-main) solid var(--color-secondary-800);
  background:#fff;
  color:var(--color-secondary-800);
  cursor:pointer;
}
.ab-radio{border-radius:100vw}

.ab-radio::after,
.ab-checkbox::after{
  content:'';
  inline-size:70%;
  block-size:70%;
  background:currentColor;
  opacity:0;
  transform:scale(0);
  /* The original's timing, copied exactly: .3s on this curve, so the dot
     arrives with a small overshoot-free settle rather than appearing. */
  transition:opacity .3s cubic-bezier(0,.55,.45,1),
             transform .3s cubic-bezier(0,.55,.45,1);
}
.ab-radio::after{border-radius:100vw}

.ab-radio:checked::after,
.ab-checkbox:checked::after{opacity:1;transform:scale(1)}

@media (prefers-reduced-motion: reduce){
  .ab-radio::after,
  .ab-checkbox::after{transition:none}
}

.ab-terms{padding-block:0}

/* --- Minimum spend ---------------------------------------------------------
   Twelve rows of month-and-amount. A list rather than a table: there is one
   value per month, so the second axis a <table> implies does not exist. */
.ab-minimum{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:.3rem;
  padding:var(--space-tight);
  background:var(--surface-tint);
}
.ab-minimum__list{
  display:grid;
  grid-template-columns:var(--ab-cols);
  gap:0 var(--space-tight);
  margin-block-start:var(--space-hair);
}
.ab-minimum__row{
  display:flex;
  justify-content:space-between;
  align-items:baseline;
  gap:var(--space-hair);
  padding-block:.35rem;
  border-block-end:var(--border-width-main) solid var(--border-color-hairline);
  font-size:var(--type-sm);
}
.ab-minimum__month{font-weight:var(--font-body-medium);color:var(--text-heading)}
.ab-minimum__amount{font-variant-numeric:tabular-nums;color:var(--text-muted)}

/* --- The parked notice -----------------------------------------------------
   This is the only thing standing between a visitor and a form that looks
   live but silently drops their enquiry, so it is stated plainly and given
   the page's own voice rather than a warning colour. It disappears with the
   button's `disabled` when an endpoint is wired up. */
.ab-form__parked{
  max-inline-size:var(--measure-prose);
  padding:var(--space-tight);
  border:var(--border-width-main) dashed var(--border-color);
  background:var(--surface-tint);
  font-size:var(--type-sm);
  line-height:var(--line-height-relaxed);
}

.ab-form__actions{
  display:flex;
  flex-flow:row wrap;
  align-items:center;
  gap:var(--space-tight);
}
/* A disabled control still has to read as text, so this stops well short of
   the 50% that would drop it under the contrast floor. */
.ab-form__actions .btn:disabled{
  opacity:.55;
  cursor:not-allowed;
}

/* --- The date picker -------------------------------------------------------
   Hand-built because <input type="date"> cannot grey out individual dates and
   this form has to show which are already taken. The reasoning is at the top of
   components/abonnering-form/abonnering-form.js.

   COLOUR DISCIPLINE. This is a dark ground: --surface-page is slate and the
   text on it is cream. Two traps were hit writing this and are recorded so the
   next person does not hit them again:

     - --piren-slate IS --surface-page (both #3b495b), so "slate on the page"
       is invisible. The filled state uses the established --button-bg /
       --button-text pair instead, which is the one contrast-checked filled
       control this site already has.
     - --color-error (#e74444) on this ground is about 2.3:1 — nowhere near the
       4.5:1 floor. So an error is NEVER signalled by text colour here. The text
       stays the readable body colour and the signal is a coral rule beside it,
       which is also the accessible answer: meaning is not carried by colour
       alone, so it survives a colour-blind reader and a greyscale print.

   Everything is styled for the KEYBOARD as much as the pointer: the grid is a
   roving-tabindex widget, so the focus ring has to be unmistakable or the whole
   thing is unusable without a mouse. It inherits the site's --focus-ring-*.  */
.ab-field--date{position:relative}

.ab-dp{position:relative;display:flex;align-items:stretch;gap:.4rem}
.ab-dp__input{flex:1;min-inline-size:0;font-variant-numeric:tabular-nums}

.ab-dp__trigger{
  flex:none;
  inline-size:2.75rem;                /* ≥44px touch target at the default root */
  border:var(--border-width-main) solid var(--border-color);
  background:var(--surface-page);
  color:var(--text-heading);
  font-size:var(--type-body);
  line-height:1;
  cursor:pointer;
  transition:var(--transition-hover);
}
.ab-dp__trigger:hover{background:var(--surface-tint)}

.ab-dp__dialog{
  position:absolute;
  inset-block-start:calc(100% + .4rem);
  inset-inline-start:0;
  z-index:var(--layer-dropdown);
  inline-size:min(20rem, calc(100vw - 2rem));
  padding:var(--space-tight);
  /* Same ground as an input, so the text on it behaves exactly like the text
     inside one — no new colour pairing is introduced. */
  background:var(--surface-page);
  border:var(--border-width-main) solid var(--border-color);
  box-shadow:var(--shadow-soft);
  animation:ab-dp-in var(--duration-fast) var(--ease-exit);
}
.ab-dp__dialog[hidden]{display:none}

@keyframes ab-dp-in{from{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){
  .ab-dp__dialog{animation:none}
}

.ab-dp__head{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--space-hair);
  margin-block-end:var(--space-hair);
}
.ab-dp__month{
  flex:1;
  text-align:center;
  font-weight:var(--font-body-medium);
  font-size:var(--type-sm);
  color:var(--text-heading);
  text-transform:capitalize;          /* sv-SE month names arrive lowercase */
}
.ab-dp__nav{
  inline-size:2.25rem;
  block-size:2.25rem;
  flex:none;
  border:var(--border-width-main) solid var(--border-color);
  background:var(--surface-page);
  color:var(--text-heading);
  font-size:var(--type-md);
  line-height:1;
  cursor:pointer;
  transition:var(--transition-hover);
}
.ab-dp__nav:hover:not(:disabled){background:var(--surface-tint)}
.ab-dp__nav:disabled{opacity:.55;cursor:not-allowed}

.ab-dp__grid{display:flex;flex-direction:column;gap:.15rem}
.ab-dp__row{display:grid;grid-template-columns:repeat(7, 1fr);gap:.15rem}
.ab-dp__weekday{
  padding-block:.25rem;
  text-align:center;
  font-size:var(--type-xs);
  font-weight:var(--font-body-medium);
  color:var(--text-heading);
}

.ab-dp__cell{
  aspect-ratio:1;
  display:flex;
  align-items:center;
  justify-content:center;
  border:var(--border-width-main) solid transparent;
  background:none;
  color:inherit;                      /* the page's own body colour, unaltered */
  font-family:var(--font-body);
  font-size:var(--type-sm);
  font-variant-numeric:tabular-nums;
  cursor:pointer;
  transition:var(--transition-hover);
}
.ab-dp__cell--empty{cursor:default}
.ab-dp__cell:hover:not([aria-disabled="true"]){background:var(--surface-tint)}

/* UNAVAILABLE. Three cues, none of them a colour change: a rule through the
   number, a hatch behind it, and the same .55 opacity the disabled submit
   already uses — which the note further up this file establishes as stopping
   short of the contrast floor. A day that is only dimmed is a day people keep
   clicking; the rule says "gone" at a glance, and it survives greyscale. */
.ab-dp__cell.is-unavailable{
  opacity:.55;
  text-decoration:line-through;
  cursor:not-allowed;
  background:repeating-linear-gradient(
    -45deg,
    transparent 0 3px,
    var(--border-color-hairline) 3px 4px
  );
}

/* The one filled control this site has a checked pair for. */
.ab-dp__cell.is-selected{
  background:var(--button-bg);
  color:var(--button-text);
  border-color:var(--button-bg);
  font-weight:var(--font-body-medium);
  opacity:1;
}

.ab-dp__legend{
  display:flex;
  align-items:center;
  gap:.5ch;
  margin-block-start:var(--space-hair);
  padding-block-start:var(--space-hair);
  border-block-start:var(--border-width-main) solid var(--border-color-hairline);
  font-size:var(--type-xs);
}
.ab-dp__swatch{
  inline-size:.9rem;
  block-size:.9rem;
  flex:none;
  border:var(--border-width-main) solid var(--border-color-hairline);
}
.ab-dp__swatch.is-unavailable{
  background:repeating-linear-gradient(
    -45deg,
    transparent 0 3px,
    var(--border-color-hairline) 3px 4px
  );
}

/* --- Errors and status -----------------------------------------------------
   Both are live regions, so they must be EMPTY until there is something to
   say: a region that ships with placeholder text announces it on load and
   teaches people to ignore the one message that will matter. :empty keeps them
   out of the layout too, so nothing reserves blank space. */
.ab-error{
  max-inline-size:var(--measure-prose);
  padding-inline-start:.8ch;
  border-inline-start:.2rem solid var(--color-accent-coral);
  font-size:var(--type-xs);
  line-height:var(--line-height-relaxed);
  font-weight:var(--font-body-medium);
}
.ab-error:empty{display:none}

.ab-input[aria-invalid="true"]{border-color:var(--color-accent-coral)}

.ab-form__status{
  max-inline-size:var(--measure-prose);
  font-size:var(--type-body);
  line-height:var(--line-height-relaxed);
}
.ab-form__status:empty{display:none}
.ab-form__status.is-busy{font-style:italic}
/* Mirrors .ab-form__parked exactly rather than inventing a second panel
   treatment — one notice style for this form, in two states. */
.ab-form__status.is-ok,
.ab-form__status.is-error{
  padding:var(--space-tight);
  border:var(--border-width-main) solid var(--border-color);
  background:var(--surface-tint);
  font-weight:var(--font-body-medium);
}
.ab-form__status.is-error{border-color:var(--color-accent-coral)}
/* The success message takes focus so a keyboard submitter lands on the
   confirmation. A focus ring on a paragraph nobody can interact with reads as
   a bug, so it is suppressed for the programmatic case only — :focus-visible
   still rings if a browser decides it should. */
.ab-form__status:focus{outline:none}
.ab-form__status:focus-visible{outline:revert}

/* --- The honeypot ----------------------------------------------------------
   Off-screen rather than display:none. Some bots skip anything display:none or
   visibility:hidden precisely because it is the obvious tell, so this stays
   technically rendered. It is aria-hidden and tabindex="-1" in the markup, so
   no human — sighted, keyboard or screen-reader — ever meets it. */
.ab-honeypot{
  position:absolute;
  inline-size:1px;
  block-size:1px;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
}


/* --- The floor plan ---------------------------------------------------------
   Three stacked images: a base plan that is always correct, plus two overlays
   that highlight which part of the venue an abonnemang covers. The overlays sit
   on top of the base, so the base must establish the box and they must not
   affect layout. */
.ab-map{
  display:block;
  inline-size:100%;
  /* figure carries a UA margin-inline of 40px; the form owns its own gutters. */
  margin:var(--space-hair) 0;
}
/* THE POSITIONING CONTEXT, and it must exclude the caption. Overlays resolve
   inset against their containing block; with the caption inside it, the box
   grew the moment the caption gained text and the overlays scaled and
   re-centred inside it — visibly out of register with the plan beneath. */
.ab-map__frame{
  position:relative;
  display:block;
  inline-size:100%;
}
.ab-map__base{
  display:block;
  inline-size:100%;
  block-size:auto;
}
.ab-map__layer{
  position:absolute;
  inset-block-start:0;
  inset-inline-start:0;
  /* Sized exactly like the base — same width, height derived the same way —
     rather than stretched to the box and letterboxed back with object-fit.
     Identical inputs, identical result, no rounding to disagree about. */
  inline-size:100%;
  block-size:auto;
  /* Cross-fade rather than snap, so a change in guest count reads as the same
     plan re-highlighting instead of a different picture. */
  transition:opacity var(--duration-medium) var(--ease-emphasis);
}
.ab-map__layer[hidden]{display:none}
@media (prefers-reduced-motion: reduce){
  .ab-map__layer{transition:none}
}
.ab-map__caption{
  margin-block-start:var(--space-hair);
  font-size:var(--type-xs);
  line-height:var(--line-height-relaxed);
  color:var(--text-muted);
}
.ab-map__caption:empty{display:none}

/* Country and discount, both added to the CMS so the rebuild can show what the
   original form shows. Only some wines carry a country, so the binding is
   conditional and the span collapses when empty. */
.ab-option__land,
.ab-option__rabatt{display:block}
.ab-option__land:empty,
.ab-option__rabatt:empty{display:none}

/* The minimum-spend figure for the chosen month. Deliberately the only price
   shown — the month-by-month table is confidential and never rendered. */
.ab-minimum__estimate{
  font-size:var(--type-md);
  font-weight:var(--font-body-medium);
  color:var(--text-heading);
}
.ab-minimum__estimate:empty{display:none}
